/**
 * @license
 * Copyright 2021 Du Tian Wei
 * SPDX-License-Identifier: Apache-2.0
 */
 import * as util from './util.js'
 export class NativeUtil {
 
     static fieldSetter(target, fieldName, register) {
         return (builder, args) => {
             let getter = builder[register][args[1] & 0xfff];
             builder.PushAction((st, f, local, pos) => {
                 let v = getter(st, f, local);
                 target[fieldName] = v;
                 return 1 + pos;
             });
         };
     }
     static fieldGetter(target, fieldName, register) {
         return (builder, args) => {
             builder[register][args[1] & 0xfff] = (st, f, local) => {
                 return target[fieldName];
             };
         };
     }
     /**
      * 
      * @param {Function} func 
      * @param {Number[]} argtype 
      * @returns 
      */
     static closureVoid(func, argtype) {
         /**
          * 
          * @param {OBFunctionBuilder} builder 
          * @param {Number[]} args 
          * @returns 
          */
         let f = (builder, args) => {
             args = args.slice(1);
             let argGetters = argtype.map((rtype, idx) => {
                 let idx1 = args[idx] & 0xFFF;
                 let v = builder[rtype][idx1];
                 return (st, f, local) => {
                     return v(st, f, local);
                 };
             });
             builder.PushAction((st, f, local, pos) => {
                 let argVals = argGetters.map(g => g(st, f, local));
                 func.apply(null, argVals);
                 return pos + 1;
             });
         };
         return f;
     }
     /**
      * 
      * @param {Function} func 
      * @param {Number[]} argtype 
      * @returns 
      */
     static closureReturnValue(func, retRegisterType, argtype) {
         /**
          * 
          * @param {OBFunctionBuilder} builder 
          * @param {Number[]} args 
          * @returns 
          */
         let f = (builder, args) => {
             let retRegIdx = args[0];
             let retType = (retRegIdx & 0xF000) >> 12;
             retRegIdx = retRegIdx & 0xFFF;
             args = args.slice(1);
             let argGetters = argtype.map((rtype, idx) => {
                 let idx1 = args[idx] & 0xFFF;
                 let v = builder[rtype][idx1];
                 return (st, f, local) => {
                     return v(st, f, local);
                 };
             });
             builder[retRegisterType][retRegIdx] = ((st, f, local) => {
                 let argVals = argGetters.map(g => g(st, f, local));
                 return func.apply(null, argVals);
             });
         };
         return f;
     }
 }
 export class OBScript {
     NativeLibHash = {}; // libname->hash
     InstalledLibs = {};
     NativeUtil = NativeUtil;
     /**
      * @type {StructData}
      */
     StructData = {}; //typename->OBStructValueData
     /**
      * @type {Object.<string,OBStructDef>}
      */
     StructDef = {}; // typename-> def
     loadedFunctions; //= {};//function sign->function
     FullNameFSMData = {}; //FullName->OBFSM
 
     /**
      * @callback FuncInstaller
      * @param {OBFunctionBuilder} funcBuilder
      * @param {number[]}  registersConfig
      */
     /**
      * 安装本地库
      * @param {string} libName
      * @param {string} jsmd5 md5 of js generated config
      * @param {FuncInstaller[]} funcInstallers array of funcInstaller
      */
     InstallLib(libName, jsmd5, funcInstallers) {
         if (this.InstalledLibs[libName]) {
             throw Error("重复导入 " + libName);
         }
         this.InstalledLibs[libName] = funcInstallers;
         this.NativeLibHash[libName] = jsmd5;
     }
     /**
          *
          * @param {string} libname
          * @param {integer} funcIdx
          */
     getNativeFunc(libname, funcIdx) {
         if (funcIdx < 0) {
             throw Error("funcIdx:" + funcIdx);
         }
         // Action < UFunctionBuilder, int[] > [] lib;
         let lib = this.InstalledLibs[libname];
         if (lib) {
             if (funcIdx < lib.length) {
                 return lib[funcIdx];
             } else {
                 throw Error("funcIdx:" + funcIdx + " of lib " + libname + " out of range " + lib.length);
             }
         } else {
             throw Error("Native lib " + libname + " not found");
         }
     }
 }
 export class OBStructDef {
     Name; //string
     StructCnt; // int
     StringCnt; // int
     IntegerCnt; // int
     FloatCnt; // int
     NobjectCnt; // int
     StructFields; // int
 }
 export class OBStructValueData {
     /**
      * @type {OBArrayBufferReader}
      */
     Data; //arraybuffer
     FullName;
     Offset;
     Length;
     StructCount;
 }
 export class OBVariableInfo {
     typeIdx;
     count;
 
     constructor(typeIdx, count) {
         this.typeIdx = typeIdx;
         this.count = count;
     }
 }
 export class OBState {
     /**
      *  @type {OBVariableInfo[]}
      */
     Variables;
     /**
      *  @type {string}
      */
     Name;
     MessageHandlers;
     EventHandlers;
 }
 export class OBCodeSegment {
     name;
     functions;
     fsms;
 }
 export class OBFunction {
     /**
      *  @type {OBVariableInfo[]}
      */
     Variables;
     instructions;
     /**
      * @type {String}
      */
     Signure;
 }
 export class OBFSM {
     /**
      * @type {string}
      */
     Name;
     /**
      * @type {Object.<string,OBState>}
      */
     States; //string->state
     /**
      * @type {OBState}
      */
     Entry; //state
     /**
      * @type {OBVariableInfo[]}
      */
     Variables;
     /**
      * @type {string}
      */
     FullName;
 }
 export class OBMessageHandler {
     Name;
     Func;
     ArgTypeName;
 }
 export class OBEventHandler {
     Name;
     Func;
 }
 export class OBInstruction {
     Position;
     /**
      *
      * @param {number} code
      * @param {OBFunctionBuilder} builder
      * @param {OBInstruction[]} instructions
      * @param {number} i
      */
     init(code, builder, instructions, i) {
 
     }
     /**
          *
          * @param {OBFunctionBuilder} funcbuilder
          * @param {OBInstruction[]} instructions
          * @param {number} i
          */
     link(funcbuilder, instructions, i) {
 
     }
 }
 export class OBByteCodes {
     static createInstruction(cmd) {
         switch (cmd) {
             //case 0:
             //    break;
             case 1:
                 return new PRT();
             case 2:
                 return new ARITHI();
             case 3:
                 return new ARITHF();
             case 4:
                 return new LDSTR();
             case 5:
                 return new LDI();
             case 6:
                 return new LDF();
             case 7:
                 return new RET();
             case 8:
                 return new STMT_start();
             case 9:
                 return new B_STMT_end();
             case 10:
                 return new CHSTT();
             case 11:
                 return new STVG();
             case 12:
                 return new FSMVS();
             case 13:
                 return new FSMVG();
             case 14:
                 return new STVS();
             case 15:
                 return new MethodCall();
             case 16:
                 return new MethodCallRegisterInfoAnchor();
             case 17:
                 return new CreateFSM();
             case 18:
                 return new FSMSendMsg();
             case 19:
                 return new ReceivedMessage();
             case 20:
                 return new GetStructField();
             case 21:
                 return new SetStructField();
             case 22:
                 return new GZ0();
             case 23:
                 return new BRIF();
             case 24:
                 return new DEC();
             case 25:
                 return new BR();
             case 26:
                 return new Reg2Var();
             case 27:
                 return new Var2Reg();
             case 28:
                 return new NOP();
             case 29:
                 return new BRIFN();
             case 30:
                 return new I2F();
             case 31:
                 return new StructFieldDesc();
             case 32:
                 return new EQ();
             case 33:
                 return new NEQ();
             case 34:
                 return new LT();
             case 35:
                 return new LTE();
             case 36:
                 return new GT();
             case 37:
                 return new GTE();
             case 38:
                 return new SLF();
             case 39:
                 return new NativeMethodCall();
             case 40:
                 return new DestroyFSM();
             case 41:
                 return new FSMBroadcastMsg();
             case 42:
                 return new SGLF();
             case 43:
                 return new RAND();
             case 44:
                 return new F2I();
             case 45:
                 return new FSMSendMsgWait_Data();
             case 46:
                 return new FSMSendMsgWait();
             case 47:
                 return new FSMBroadcastMsgWait();
             case 48:
                 return new TextJoin();
             case 49:
                 return new ToString();
             case 50:
                 return new Sender();
             case 51:
                 return new VOM();
             case 52:
                 return new SHL();
             case 53:
                 return new AND();
             case 54:
                 return new FIX();
             case 55:
                 return new LAND();
             case 56:
                 return new LOR();
             case 57:
                 return new LNOT();
             case 58:
                 return new COND();
             default:
                 throw Error("Unknown byte code command:" + cmd);
         }
         // return new OBInstruction(cmd);
     }
 }
 export class PositionUpdatePair {
     targetOffset;
     callback;
 }
 export class OBFunctionBuilder {
     loader; //OBScriptLoader
     StatementLength; //integer
     BuildingFunc; //OBFunction
     PositionUpdatePairList;
     currentInstructPosition; //integer
     CurrentStatementStack = []; //[StatementContext]
 
     /**
      *  @callback LongRegister
      * @param {OBVMState}
      * @param {OBFunctionBuilder}
      * @param {OBInstruction[]}
      * @param {number}
      * @returns {number}
      */
     /**
      * @type LongRegister[]
      */
     LongRegister;
     /**
      *  @callback DoubleRegister
      * @param {OBVMState}
      * @param {OBFunctionBuilder}
      * @param {OBInstruction[]}
      * @param {number}
      * @returns {number}
      */
     /**
      * @type DoubleRegister[]
      */
     DoubleRegister;
     /**
      *  @callback StringRegister
      * @param {OBVMState}
      * @param {OBFunctionBuilder}
      * @param {OBInstruction[]}
      * @param {number}
      * @returns {string}
      */
     /**
      * @type StringRegister[]
      */
     StringRegister;
     /**
      *  @callback StringRegister
      * @param {OBVMState}
      * @param {OBFunctionBuilder}
      * @param {OBInstruction[]}
      * @param {number}
      * @returns {OBStructValue}
      */
     /**
      * @type StructRegister[]
      */
     StructRegister;
     /**
      *  @callback StringRegister
      * @param {OBVMState}
      * @param {OBFunctionBuilder}
      * @param {OBInstruction[]}
      * @param {number}
      * @returns {object}
      */
     /**
      * @type NObjectRegister[]
      */
     NObjectRegister;
 
     constructor(loader) {
         this.loader = loader;
     }
 
     loadFunctionHeader(reader) {
         let data = this.loader.data;
         let BuildingFunc = new OBFunction();
         this.BuildingFunc = BuildingFunc;
 
         let header = reader.ReadUInt32();
         let pos = reader.pos;
         this.StatementLength = header * 4 - pos;
         reader.pos = header * 4;
         let nameIdx = reader.ReadUInt32();
         BuildingFunc.Signure = data.GetString(nameIdx);
         this.LongRegister = [];
         this.LongRegister.length = reader.ReadUInt32();
         this.DoubleRegister = [];
         this.DoubleRegister.length = reader.ReadUInt32();
         this.StringRegister = [];
         this.StringRegister.length = reader.ReadUInt32();
         this.StructRegister = [];
         this.StructRegister.length = reader.ReadUInt32();
         this.NObjectRegister = [];
         this.NObjectRegister.length = reader.ReadUInt32();
         let varInfo = [];
         for (let i = 0; i < 5; i++) {
             let info = new OBVariableInfo();
             info.typeIdx = i;
             info.count = reader.ReadUInt32();
         }
         BuildingFunc.Variables = varInfo;
         reader.pos = pos;
     }
 
     loadStatement(reader) {
         let length = this.StatementLength / 4;
         this.BuildingFunc.instructions = [];
         this.PositionUpdatePairList = []; //[PositionUpdatePair]
         for (let i = 0; i < length; i++) {
             let instPos = reader.pos;
             let code = reader.ReadUInt32();
             let cmd = (code >> 24);
             let inst = OBByteCodes.createInstruction(cmd);
             inst.Position = instPos;
             inst.init(code, this, this.BuildingFunc.instructions, i);
             this.BuildingFunc.instructions[i] = inst;
         }
     }
 
     link() {
         let instructions = this.BuildingFunc.instructions;
         for (let i = 0; i < instructions.length; i++) {
             let inst = instructions[i];
             this.currentInstructPosition = inst.Position;
             inst.link(this, instructions, i);
         }
         this.PositionUpdatePairList = null;
         this.BuildingFunc.Statements = this.RootStatementContext;
     }
 
     build() {
         return this.BuildingFunc;
     }
 
     PositionUpdate(targetOffset, callback) {
         if (this.PositionUpdatePairList == null) {
             throw Error("异常状态");
         }
         let p = new PositionUpdatePair();
         p.targetOffset = targetOffset;
         p.callback = callback;
         this.PositionUpdatePairList.push(p);
     }
 
     PushAction(Instruction) {
         let stmt = this.CurrentStatementStack[this.CurrentStatementStack.length - 1];
         let newPos = stmt.Actions.length;
         stmt.PushAction(Instruction);
         this.PositionUpdatePairList.forEach((p) => {
             if (p.targetOffset == this.currentInstructPosition) {
                 p.callback(newPos);
             }
         });
     }
 }
 
 export class OBBuildInFunctions {
     /**
      * 
      * @param {OBScript} script 
      */
     static install(script) {
         script.InstallLib("", "", [
             OBBuildInFunctions.FSM_FindFsmByTypeInstaller,
             OBBuildInFunctions.FSM_FindFsmByNameInstaller,
             OBBuildInFunctions.Structs_LoadStructFromDatasetInstaller,
             // OBBuildInFunctions.FSM_TargetInstaller,
             script.NativeUtil.closureReturnValue(OBBuildInFunctions.Text_Length, 'LongRegister', ['StringRegister']),
             script.NativeUtil.closureReturnValue(OBBuildInFunctions.Text_IsEmpty, 'LongRegister', ['StringRegister']),
             script.NativeUtil.closureReturnValue(OBBuildInFunctions.Text_IndexOf, 'LongRegister', ['StringRegister', 'StringRegister', 'LongRegister']),
             script.NativeUtil.closureReturnValue(OBBuildInFunctions.Text_CharAt, 'StringRegister', ['StringRegister', 'LongRegister']),
             script.NativeUtil.closureReturnValue(OBBuildInFunctions.Text_GetSubstring, 'StringRegister', ['StringRegister', 'LongRegister', 'LongRegister']),
             script.NativeUtil.closureReturnValue(OBBuildInFunctions.Text_ToUpperCase, 'StringRegister', ['StringRegister']),
             script.NativeUtil.closureReturnValue(OBBuildInFunctions.Text_ToLowerCase, 'StringRegister', ['StringRegister']),
             script.NativeUtil.closureReturnValue(OBBuildInFunctions.Text_ToTitleCase, 'StringRegister', ['StringRegister']),
             script.NativeUtil.closureReturnValue(OBBuildInFunctions.Text_Count, 'LongRegister', ['StringRegister', 'StringRegister']),
             script.NativeUtil.closureReturnValue(OBBuildInFunctions.Text_Replace, 'StringRegister', ['StringRegister', 'StringRegister', 'StringRegister']),
             script.NativeUtil.closureReturnValue(OBBuildInFunctions.Text_Reverse, 'StringRegister', ['StringRegister']),
         ]);
     }
     /**
      * 
      * @param {String} str 
      * @returns 
      */
     static Text_Reverse(str) {
         if (str) {
             return str.split('').reverse().join('');
         } else {
             return "";
         }
     }
     static Text_Replace(haystack, needle, replacement) {
         needle = needle.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, "\\$1")
             .replace(/\x08/g, "\\x08");
         return haystack.replace(new RegExp(needle, 'g'), replacement);
     }
     static Text_Count(haystack, needle) {
         if (needle.length === 0) {
             return haystack.length + 1;
         } else {
             return haystack.split(needle).length - 1;
         }
     }
     /**
      * 
      * @param {String} str 
      * @returns 
      */
     static Text_ToTitleCase(str) {
         return str.replace(
             /\w\S*/g,
             function (txt) {
                 return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
             }
         );
     }
     /**
      * 
      * @param {String} str 
      * @returns 
      */
     static Text_ToLowerCase(str) {
         if (str) {
             return str.toLowerCase();
         }
         return "";
     }
     /**
      * 
      * @param {String} str 
      * @returns 
      */
     static Text_ToUpperCase(str) {
         if (str) {
             return str.toUpperCase();
         }
         return "";
     }
     static Text_GetSubstring(str, from, to) {
         let start = from;
         if (start < 0) {
             start = str.length + start;
         } else {
             start -= 1;
         }
         let end = to;
         if (end < 0) {
             end = str.length + to;
         } else {
             end -= 1;
         }
         if (start > end) {
             let t = start;
             start = end;
             end = t;
         }
         return str.substring(start, end + 1);
     }
     static Text_CharAt(str, index) {
         if (index === 0) {
             return "";
         }
         if (index > 0) {
             return str[index - 1] || "";
         }
         if (index < 0) {
             return str[str.length + index];
         }
     }
     static Text_IndexOf(str, sub, forward) {
         if (forward == 1) {
             return str.indexOf(sub) + 1;
         } else {
             return str.lastIndexOf(sub) + 1;
         }
     }
     static Text_IsEmpty(str) {
         return str.length === 0 ? 1 : 0;
     }
     static Text_Length(str) {
         return str.length;
     }
     static FSM_FindFsmByTypeInstaller(builder, args) {
         let returnRegisterIdx = args[0] & 0xFFF;
         let argIdx = args[1] & 0xFFF;
         let a1 = builder.StringRegister[argIdx];
         builder.NObjectRegister[returnRegisterIdx] = (state, func, locals) => {
             let r = state.fsm.VM.FindRunningFSMByType(a1(state, func, locals));
             return r;
         };
     }
     static FSM_FindFsmByNameInstaller() {
     }
     static Structs_LoadStructFromDatasetInstaller(builder, args) {
         let returnRegisterIdx = args[0] & 0xFFF;
         let idIdx = args[2] & 0xFFF;
         let a1 = builder.LongRegister[idIdx];
         let typeIdx = args[1] & 0xFFF;
         let a2 = builder.StringRegister[typeIdx];
         let StructData = builder.loader.script.StructData;
         builder.StructRegister[returnRegisterIdx] = (state, func, locals) => {
             let r = StructData.Get(a2(state, func, locals), a1(state, func, locals));
             return r;
         };
     }
     static FSM_TargetInstaller(builder, args) {
         let returnRegisterIdx = args[0] & 0xFFF;
         builder.NObjectRegister[returnRegisterIdx] = (state, func, locals) => {
             return state.fsm.Target;
         };
     }
 }
 export class OBStructValue {
     /**
      * @type {OBStructDef}
      */
     Def;
     /**
      * @type {OBTypedVariableGroup}
      */
     registers;
 
     constructor(Def) {
         this.Def = Def;
         let registers = new OBTypedVariableGroup();
         registers.LongRegister = [];
         registers.LongRegister.length = Def.IntegerCnt;
         registers.DoubleRegister = [];
         registers.DoubleRegister.length = Def.FloatCnt;
         registers.StringRegister = [];
         registers.StringRegister.length = Def.StringCnt;
         registers.StructRegister = [];
         registers.StructRegister.length = Def.StructCnt;
         registers.NObjectRegister = [];
         registers.NObjectRegister.length = Def.NobjectCnt;
         this.registers = registers;
     }
 
     toString() {
         return "Struct." + this.Def.Name;
     }
 }
 export class StructData {
     /**
      * @type {Object.<string,OBStructDef>}
      */
     StructDef;
     /**
      * @type {Object.<string,OBStructValueData>}
      */
     Groups;
     /**
      * @type {OBArrayBufferReader}
      */
     DataSegment;
 
     constructor(structDataGroups, data) {
         this.Groups = structDataGroups;
         this.DataSegment = data;
     }
     /**
          *
          * @param {string} type fullname of type
          * @param {integer} id id of data
          * @param {?Object.<string,OBStructValue>}
          * @returns {OBStructValue}
          */
     Get(type, id, loading) {
         if (type.startsWith("S") && type.endsWith(";")) {
             type = type.substr(1, type.length - 2);
         }
         if (loading == null) {
             loading = {};
         } else {
             let loaded = loading[id + "@" + type];
             if (loaded) {
                 return loaded;
             }
         }
         let def = this.StructDef[type];
         let group = this.Groups[type];
         let reader = group.Data;
         let itemStart = 0;
         for (let i = 0; i < group.StructCount; i++) {
             reader.pos = itemStart;
             let length = reader.ReadInt32();
             let itemid = reader.ReadUInt32();
             if (itemid == id) {
                 reader.pos -= 4;
                 let s = new OBStructValue(def);
                 loading[id + "@" + type] = s;
                 for (let j = 0; j < def.IntegerCnt; j++) {
                     s.registers.LongRegister[j] = reader.ReadInt32(); //VariableValueSet(j, reader.ReadInt32());
                 }
                 for (let j = 0; j < def.StringCnt; j++) {
                     let idx = reader.ReadUInt32();
                     let str = this.DataSegment.GetString(idx);
                     s.registers.StringRegister[j] = str; //VariableValueSet(j, str);
                 }
                 for (let j = 0; j < def.FloatCnt; j++) {
                     s.registers.DoubleRegister[j] = reader.ReadSingle(); //VariableValueSet(j, reader.ReadSingle());
                 }
                 for (let j = 0; j < def.StructCnt; j++) {
                     let fieldDef = def.StructFields[j];
                     if (fieldDef.startsWith("S")) {
                         let subId = reader.ReadUInt32();
                         let subStruct = this.Get(def.StructFields[j], subId, loading);
                         s.registers.StructRegister[j] = subStruct; //VariableValueSet(j, subStruct);
                     } else if (fieldDef.startsWith("I")) {
                         // TODO
                     } else if (fieldDef.startsWith("N")) {
                         let elementTypeName = fieldDef.substr(1);
                         let structCnt = reader.ReadUInt32();
                         let map = {};
                         for (let k = 0; k < structCnt; k++) {
                             let keyIdx = reader.ReadUInt32();
                             let keyStr = this.DataSegment.GetString(keyIdx);
                             let structId = reader.ReadInt32();
                             let st = this.Get(elementTypeName, structId, loading);
                             map[keyStr] = st;
                         }
                         s.registers.StructRegister[j] = map;
                     }
                 }
                 return s;
             } else {
                 itemStart += length * 4 + 4;
             }
         }
         throw Error("找不到 ID为" + id + "的" + type);
     }
 }
 
 export class OBStructDataReader {
     /**
      * 
      * @param {OBArrayBufferReader} reader 
      * @returns {StructData}
      */
     readStream(reader) {
         let dataLength = reader.ReadUInt32();
         let data = reader.readSub(dataLength);
         return this.readStructData(reader, data);
     }
     /**
      * 
      * @param {OBArrayBufferReader} reader 
      * @param {OBArrayBubberReader} data 
      * @returns {StructData}
      */
     readStructData(reader, data) {
         let length = reader.ReadInt32();
         let structs = {};
 
         let groupCnt = reader.ReadUInt32();
         for (let i = 0; i < groupCnt; i++) {
             let offset = reader.pos;
             let strIdx = reader.ReadUInt32();
             let FullName = data.GetString(strIdx);
             let structCnt = reader.ReadInt32();
             let length = reader.ReadInt32();
             // arraybuffer
             let bin = reader.readSub(length * 4);
             let info = new OBStructValueData(); //
             info.Data = bin;
             info.FullName = FullName;
             info.Offset = offset;
             info.Length = length;
             info.StructCount = structCnt;
             structs[FullName] = info;
         }
         return new StructData(structs, data);
     }
 }
 class Relocation {
     /**
      * @type {Object.<String:{idx:Number,inited:bool}>}
      */
     string = {};
     /**
      * @type {Object.<String:{idx:Number,inited:bool}>}
      */
     integer = {};
     /**
      * @type {Object.<String:{idx:Number,inited:bool}>}
      */
     float = {};
     /**
      * @type {Object.<String:{idx:Number,inited:bool}>}
      */
     bin = {};
     /**
      * @type {Object.<String:{idx:Number,inited:bool}>}
      */
     structFieldIndex = {};
 
     addRelocationString(str) {
         if ((typeof str) !== 'string') {
             throw Error('不是字符串');
         }
         if (!this.string.hasOwnProperty(str)) {
             this.string[str] = {
                 idx: 0,
                 inited: false
             }
         }
     }
 }
 export class OBStructDataSerializer {
     relocation = new Relocation();
     /**
      * 
      * @param {OBStructValue[]} valueData 
      * @returns {int[]}
      */
     serialize(valueDataArray) {
         let group = this.groupData(valueDataArray);
     }
     /**
      * 
      * @param {OBStructValue[]} valueDataArray 
      * @returns {Object.<String,OBStructValue[]}
      */
     groupData(valueDataArray) {
         let group = {};
         valueDataArray.forEach(d => {
             let list = group[d.Def.Name];
             if (!list) {
                 list = [];
                 group[d.Def.Name] = list;
             }
             this.collData(d);
             list.push(d);
         });
         return group;
     }
     /**
      * 
      * @param {OBStructValue} d 
      */
     collData(d) {
         d.string.forEach(str => {
             this.relocation.addRelocationString(str);
         });
         d.registers.object.forEach(ofd => {
             switch (ofd.type.$__type) {
                 case "StructFieldTypeStruct":
                     break;
                 case "StructFieldTypeIntegerMap":
                     switch (ofd.type.elementType.name) {
                         case 'string':
                         case 'String':
                             Object.values(item.registers.object[ofd.registerIndex]).forEach(str => {
                                 this.addRelocationString(str);
                             });
                     }
                     break;
                 case "StructFieldTypeStringMap":
                     switch (ofd.type.elementType.name) {
                         case 'string':
                         case 'String':
                             Object.values(item.registers.object[ofd.registerIndex]).forEach(str => {
                                 this.addRelocationString(str);
                             });
                     }
                     Object.keys(item.registers.object[ofd.registerIndex]).forEach(str => {
                         this.addRelocationString(str);
                     });
                     break;
                 case "StructFieldTypeList":
                     switch (ofd.type.elementType.name) {
                         case 'string':
                         case 'String':
                             Object.values(item.registers.object[ofd.registerIndex]).forEach(str => {
                                 this.addRelocationString(str);
                             });
                     }
                     break;
                 default:
                     console.error(ofd);
                     throw Error("功能未实现 " + ofd.type.$__type);
             }
         });
     }
 }
 export class OBScriptLoader {
     /**
      * @type {OBArrayBufferReader}
      */
     reader; //OBArrayBufferReader
     /**
      * @type {OBArrayBufferReader}
      */
     data; //OBArrayBufferReader
     loadingFunctions = {}; //[OBFunctionBuilder]
     Linkings = []; //Linkable
 
     /**
      * @callback NativeLibInstaller
      * @param {OBScript} script
      */
     /**
      *
      * @param {ArrayBuffer} arraybuffer of byte code
      * @param {NativeLibInstaller} nativeLibs
      * @returns
      */
     static loadScript(arraybuffer, nativeLibs) {
         let script = new OBScript();
         OBBuildInFunctions.install(script);
         let l = new OBScriptLoader();
         // let nativeLibs = OBNative.functions;
         if (nativeLibs) {
             if (Array.isArray(nativeLibs)) {
                 nativeLibs.forEach(installer => {
                     installer(script);
                 });
             } else {
                 nativeLibs(script);
             }
         }
         l.load(script, arraybuffer);
         return script;
     }
     load(script, buf) {
         this.script = script;
         this.reader = new OBArrayBufferReader(buf);
         this.readXE();
     }
 
     readXE() {
         let MAG = this.reader.ReadInt32(); //'\u007fUEX';
         if (MAG != 0x5845557F) {
             throw Error("Unknown MAG:" + MAG);
         }
         let version = this.reader.ReadInt32();
         if (version != 1) {
             throw Error("Unsupported version." + version);
         }
 
         let SegmentCnt = this.reader.ReadInt32();
         let headerEnd = this.reader.pos + SegmentCnt * 2 * 4;
 
         let codes = [];
 
         for (let i = 0; i < SegmentCnt; i++) {
             let type = this.reader.ReadInt32();
             let startIn4Bytes = this.reader.ReadUInt32();
             let start = headerEnd + startIn4Bytes * 4;
             let pos = this.reader.pos;
             switch (type) {
                 case 0:
                     this.reader.seek(start);
                     this.data = this.loadDataSegment();
                     break;
                 case 1:
                     this.reader.seek(start);
                     let code = this.loadCodeSegment(); // data应该是第一个段，所以此时data已经存在
                     codes.push(code);
                     break;
                 case 2:
                     this.reader.seek(start);
                     this.script.StructData = this.loadStructDataSegment();
                     this.script.StructData.StructDef = this.script.StructDef;
                     break;
                 case 3:
                     this.reader.seek(start);
                     this.script.StructDef = this.loadStructDefDataSegment();
                     break;
                 case 4:
                     this.reader.seek(start);
                     this.loadPackageInfo();
                     break;
                 default:
                     throw new FileLoadException("Unknown Segment type:" + type);
             }
             this.reader.seek(pos);
         }
         this.script.loadedFunctions = this.loadingFunctions;
         this.Linkings.forEach(l => {
             l.link();
         });
         codes.forEach(codeSeg => {
             codeSeg.fsms.forEach(fsm => {
                 fsm.FullName = codeSeg.name + "." + fsm.Name;
                 this.script.FullNameFSMData[fsm.FullName] = fsm;
             });
         });
     }
 
     loadCodeSegment() {
         let reader = this.reader;
         let data = this.data;
 
         let start = reader.pos;
         let SegmentReader = reader.getSub(start);
 
         let header = SegmentReader.ReadUInt32() * 4;
         SegmentReader.pos = header;
         let segment = new OBCodeSegment();
         let nameStringIdx = SegmentReader.ReadInt32();
         let name = data.GetString(nameStringIdx);
         let ufunctions = this.readFunctions(SegmentReader);
         let fsms = this.readFSMs(SegmentReader, name);
         // 字段赋值
         segment.name = name;
         segment.functions = ufunctions;
         segment.fsms = fsms;
         return segment;
     }
 
     readFSMs(reader, moduleName) {
         let cnt = reader.ReadInt32();
         let f = []; // [OBFSM]
         for (let i = 0; i < cnt; i++) {
             let s = reader.ReadUInt32() * 4;
             let pos = reader.pos;
             reader.pos = s;
             let fsm = this.readFSM(reader);
             fsm.ModuleName = moduleName;
             fsm.FullName = moduleName + "." + fsm.Name;
             reader.pos = pos;
             f[i] = fsm;
         }
         return f;
     }
 
     readFSM(reader) {
         let data = this.data;
         let nameIdx = reader.ReadUInt32();
         let name = data.GetString(nameIdx);
         let variables = this.readVariables(reader);
         let fucCnt = reader.ReadUInt32();
         // TODO
         let states = this.readStates(reader);
         let entryStateNameIdx = reader.ReadUInt32();
         let entryStateName = data.GetString(entryStateNameIdx);
         let entryState = null;
 
         // Dictionary<string, UState> stateDict = new Dictionary<string, UState>();
         let stateDict = {};
         for (let i = 0; i < states.length; i++) {
             let s = states[i];
             stateDict[s.Name] = s;
             if (entryStateName == s.Name) {
                 entryState = s;
             }
         }
         if (entryState == null) {
             throw Error("Can't find state named " + entryStateName + " FSM " + name);
         }
         let fsm = new OBFSM();
         fsm.Name = name;
         fsm.States = stateDict;
         fsm.Entry = entryState;
         fsm.Variables = variables;
         return fsm;
     }
 
     readStates(reader) {
         let cnt = reader.ReadInt32();
         let r = []; //[OBState]
         for (let i = 0; i < cnt; i++) {
             let s = reader.ReadUInt32() * 4;
             let p = reader.pos;
             reader.pos = s;
             r.push(this.readState(reader));
             reader.pos = p;
         }
         return r;
     }
 
     readState(reader) {
         let data = this.data;
         let nameIdx = reader.ReadUInt32();
         let name = data.GetString(nameIdx);
         let variables = this.readVariables(reader);
         // 读取函数
         this.readFunctions(reader);
         // UMessageHandler[]
         let handlers = this.readHandlers(reader);
         // UEventHandler[]
         let ehandlers = this.readEHandlers(reader);
         // Dictionary<string, List<UMessageHandler>> Mh = new Dictionary<string, List<UMessageHandler>>();
         let Mh = {};
         for (let i = 0; i < handlers.length; i++) {
             let h = handlers[i];
             let hl = Mh[h.Name];
             if (hl) {
             } else {
                 hl = []; //new List<UMessageHandler>();
                 Mh[h.Name] = hl;
             }
             hl.push(h);
         }
         // Dictionary<string, UEventHandler> eh = new Dictionary<string, UEventHandler>();
         let eh = {};
         for (let i = 0; i < ehandlers.length; i++) {
             let h = ehandlers[i];
             eh[h.Name] = h;
         }
         let r = new OBState();
         r.Variables = variables;
         r.Name = name;
         r.MessageHandlers = Mh;
         r.EventHandlers = eh;
         return r;
     }
 
     readEHandlers(reader) {
         let cnt = reader.ReadInt32();
         // UEventHandler[] f = new UEventHandler[cnt];
         let f = [];
         for (let i = 0; i < cnt; i++) {
             let start = reader.ReadUInt32() * 4;
             let h = this.readEHandler(reader, start);
             f[i] = h;
         }
         return f;
     }
 
     readEHandler(reader, start) {
         let pos = reader.pos;
         reader.pos = start;
         let func = this.readFunction(reader);
         let h = new OBEventHandler();
         h.Name = func.Signure;
         h.Func = func;
         reader.pos = pos;
         return h;
     }
 
     readHandlers(reader) {
         let cnt = reader.ReadUInt32();
         // UMessageHandler[] f = new UMessageHandler[cnt];
         let f = [];
         for (let i = 0; i < cnt; i++) {
             let start = reader.ReadUInt32() * 4;
             let h = this.readHandler(reader, start);
             f[i] = h;
         }
         return f;
     }
 
     readHandler(reader, start) {
         let pos = reader.pos;
         reader.pos = start;
         let func = this.readFunction(reader);
         let h = new OBMessageHandler();
         let pair = func.Signure.split(':');
         h.Name = pair[0];
         h.Func = func;
         h.ArgTypeName = pair[1];
         reader.pos = pos;
         return h;
     }
 
     readVariables(reader) {
         let data = this.data;
         let varCnt = reader.ReadUInt32();
         // List<UVariableInfo> d = new List<UVariableInfo>();
         let d = [];
         for (let i = 0; i < varCnt; i++) {
             let v = this.readVariable(reader);
             d.push(v);
         }
         return d;
     }
 
     readVariable(reader) {
         let typeIdx = reader.ReadInt32();
         let count = reader.ReadInt32();
         let v = new OBVariableInfo(typeIdx, count);
         return v;
     }
 
     readFunctions(reader) {
         let cnt = reader.ReadInt32();
         let f = [];
         for (let i = 0; i < cnt; i++) {
             let start = reader.ReadUInt32() * 4;
             let pos = reader.pos;
             reader.pos = start;
             let _f = this.readFunction(reader);
             f[i] = _f;
             this.loadingFunctions[_f.Signure] = _f;
             reader.pos = pos;
         }
         return f;
     }
 
     readFunction(reader) {
         let builder = new OBFunctionBuilder(this);
         builder.loadFunctionHeader(reader);
         builder.loadStatement(reader);
         this.addLinking(builder);
         let f = builder.build();
         return f;
     }
 
     addLinking(l) {
         this.Linkings.push(l);
     }
 
     loadStructDataSegment() {
         let reader = this.reader;
         let data = this.data;
         return new OBStructDataReader().readStructData(reader, data);
     }
     /**
          *
          * @returns {Object.<string,OBStructValueData>}
          */
     loadStructDefDataSegment() {
         let reader = this.reader;
         let data = this.data;
         let length = reader.ReadInt32();
         let d = {};
         let cnt = reader.ReadInt32();
         for (let i = 0; i < cnt; i++) {
             let nameIdx = reader.ReadUInt32();
             let name = data.GetString(nameIdx);
             let typeCnt = reader.ReadUInt32();
             let structCnt = (typeCnt & 0x7F);
             let stringCnt = ((typeCnt >> 7) & 0x7F);
             let integerCnt = ((typeCnt >> 14) & 0x7F);
             let floatCnt = ((typeCnt >> 21) & 0x7F);
             let NobjectCnt = ((typeCnt >> 28));
             // string[] fields = new string[structCnt];
             let fields = [];
             for (let j = 0; j < structCnt; j++) {
                 let fnameIdx = reader.ReadUInt32();
                 let fname = data.GetString(fnameIdx);
                 fields[j] = fname;
             }
             let s = new OBStructDef();
             s.Name = name;
             s.StructCnt = structCnt;
             s.StringCnt = stringCnt;
             s.IntegerCnt = integerCnt;
             s.FloatCnt = floatCnt;
             s.NobjectCnt = NobjectCnt;
             s.StructFields = fields;
             d[name] = s;
         }
         return d;
     }
 
     loadDataSegment() {
         let length = this.reader.ReadInt32();
         return this.reader.readSub(length * 4);
     }
 
     loadPackageInfo() {
         let reader = this.reader;
         let data = this.data;
         let depCnt = reader.ReadInt32();
         let err = [];
         for (let i = 0; i < depCnt; i++) {
             let nameIdx = reader.ReadInt32();
             let name = data.GetString(nameIdx);
             let hashIdx = reader.ReadInt32();
             let hash = data.GetString(hashIdx);
             let lhash = this.script.NativeLibHash[name];
             if (!lhash) {
                 err.push("No native lib named " + name);
             } else if (lhash != hash) {
                 err.push("Native lib hash mismatching." + name + " require " + hash + ", provide " + lhash);
             }
         }
         if (err.length > 0) {
             // throw err;
             console.error(err);
         }
     }
 }
 
 export class OBArrayBufferReader {
     /**
      * @type {Number} integer of position
      */
     pos; // int
     /**
      * @type {ArrayBuffer}
      */
     buf; // ArrayBuffer
     /**
      * @type DataView
      */
     view; // DataView
     /**
      * @type {Object.<Number,String>}
      */
     stringCache = {};
 
     constructor(buf) {
         this.buf = buf;
         this.pos = 0;
         this.view = new DataView(buf);
     }
 
     ReadInt32() {
         let v = this.getInt32(this.pos);
         this.pos += 4;
         return v;
     }
 
     getInt32(p) {
         let v = this.view.getInt32(p, true);
         return v;
     }
 
     ReadUInt32() {
         let v = this.getUint32(this.pos, true);
         this.pos += 4;
         return v;
     }
 
     getUint32(p) {
         let v = this.view.getUint32(p, true);
         return v;
     }
 
     ReadSingle() {
         let v = this.getFloat(this.pos);
         return v;
     }
 
     getFloat(p) {
         let v = this.view.getFloat32(p, true);
         return v;
     }
 
     GetString(stringIdx) {
         let start = stringIdx * 8; // 字符串是8字节对齐
         let length = this.view.getUint32(start, true);
         if (length == 0) {
             return "";
         }
         let ab = this.buf.slice(start + 4, start + 4 + length);
         let ui8 = new Uint8Array(ab);
         let utf8decoder = new util.TextDecoder("utf-8", {
             fatal: true
         });
         let str = utf8decoder.decode(ui8);
         if (str == null) {
             throw Error('no string value of idx:' + stringIdx);
         }
         return str;
     }
 
     readSub(length) {
         let v = this.getSub(this.pos, length);
         this.pos += length;
         return v;
     }
 
     getSub(pos, length) {
         let buf;
         if (typeof (length) == "undefined") {
             buf = this.buf.slice(pos);
         } else {
             buf = this.buf.slice(pos, pos + length);
         }
         return new OBArrayBufferReader(buf);
     }
 
     seek(pos) {
         if (typeof (pos) == "number") {
             this.pos = pos;
         }
         return this.pos;
     }
     /**
          *
          * @param {Number} startIdx
          * @returns {number[]}
          */
     GetInt32FromBin(startIdx) {
         let start = startIdx * 8; // 8字节对齐
         let p = this.pos;
         this.pos = start;
         let byteLength = this.ReadUInt32();
         let length = byteLength / 4;
         let r = [];
         for (let i = 0; i < length; i++) {
             r.push(this.ReadInt32());
         }
         this.pos = p;
         return r;
     }
 }
 
 
 export class OBStatementContext {
     InstPos;
     Actions = [];
 
     PushAction(Instruction) {
         this.Actions.push(Instruction);
     }
 }
 // 虚拟机
 
 export class VMInterruptException {
 }
 export class ChangeStateException extends VMInterruptException {
 }
 export class ChangeDestroyException extends VMInterruptException {
 }
 export class OBVM {
     /**
      * @type {function(any)}
      */
     Output;
     /**
      * typeName->[VMFSM]
      * @type {Object.<string:OBVMFSM[]>}
      */
     Running = {};
     /**
      * @type OBScript
      */
     script;
     /**
      * @type {OBVMFSM}
      */
     Pending = [];
     /**
      *
      * @param {OBScript} script
      */
     constructor(script) {
         if (!script) {
             throw Error("Script is null");
         }
         this.script = script;
     }
 
     CreateFSM(name) {
         if (name == null) {
             return null;
         }
         if (this.script == null) {
             throw Error("Script is null");
         }
         let fsmdata = this.script.FullNameFSMData[name];
         if (!fsmdata) {
             return null;
         }
         let uBFSM = new OBVMFSM(this, fsmdata);
         let list = this.Running[name];
         if (!list) {
             list = [];
             this.Running[name] = list;
         }
         list.push(uBFSM);
         return uBFSM;
     }
 
     update() {
         this._HandleOnePendingFSM();
         let timestamp = Date.now();
         // JS不需要在VM中处理计划任务
         // this._HandleSchedulingTask(timestamp);
         // this._InvokeScheduledTask(timestamp);
     }
 
     _HandleOnePendingFSM() {
         while (this.Pending.length > 0) {
             let fsm = this.Pending.shift();
             if (fsm) {
                 fsm.HandleAllMessages();
             }
         }
     }
     /**
          *
          * @param {OBVMFSM} fsm
          */
     _AddPendingFSM(fsm) {
         this.Pending.push(fsm);
     }
 
     Log(v) {
         console.log(v);
         if (this.Output) {
             this.Output(v);
         }
     }
     /**
          *
          * @param {OBVMFSM} fsm
          */
     DestroyFSM(fsm) {
         let name = fsm.data.FullName;
         let list = this.Running[name];
         if (list) {
             let idx = list.findIndex((f) => f == fsm);
             if (idx > -1) {
                 list.splice(idx, 1);
             }
         }
     }
     /**
          *
          * @param {OBUserMessage} userMessage
          */
     BroadcastMessage(userMessage) {
         Object.values(this.Running).forEach(l => {
             for (let i = 0; i < l.length; i++) {
                 let f = l[i];
                 if (f && f != userMessage.sender) {
                     f.PostMessage(userMessage);
                 }
             }
         });
     }
     /**
          *
          * @param {number} millisecond wait time
          * @param {OBVMAction} callback
          */
     Schedule(millisecond, callback) {
         setTimeout(callback, millisecond, this);
     }
 
     FindRunningFSMByType(typeFullName) {
         return this.Running[typeFullName] || [];
     }
 }
 export class OBVMFSM {
     static ID_GEN = 0;
     /**
      * @type {any}
      */
     Target;
     /**
      * @type {OBFSM}
      */
     data;
     id;
     /**
      * @type {OBVMState}
      */
     CurrentState;
     /**
      * @type {OBVMState[]}
      */
     StateStack = [];
     /**
      * @type {OBVM}
      */
     VM;
     Inbox = [];
     PrioritizedInbox = [];
     VariableGroup;
     /**
      *
      * @param {OBVM} vm
      * @param {OBFSM} data
      */
     constructor(vm, data) {
         this.data = data;
         this.id = ++OBVMFSM.ID_GEN;
         this.VM = vm;
         this.VariableGroup = new OBTypedVariableGroup(data.Variables);
         this.CurrentState = new OBVMState(data.Entry, this);
         this.PostPrioritizedMessage(new OBEventMessage("Start", "", null));
     }
     /**
          * 推送高优先级消息
          * @param {OBMessage} msg
          */
     PostPrioritizedMessage(msg) {
         if (this.PrioritizedInbox == null) {
             return;
         }
         this.PrioritizedInbox.push(msg);
         this.VM._AddPendingFSM(this);
     }
     /**
          * 推送消息
          * @param {OBMessage} msg
          */
     PostMessage(msg) {
         if (this.Inbox == null) {
             return;
         }
         this.Inbox.push(msg);
         this.VM._AddPendingFSM(this);
     }
 
     HandleAllMessages() {
         let msg;
         while (msg = this.PrioritizedInbox.shift()) {
             msg.Handle(this.CurrentState);
         }
         while (msg = this.Inbox.shift()) {
             msg.Handle(this.CurrentState);
             while (msg = this.PrioritizedInbox.shift()) {
                 msg.Handle(this.CurrentState);
             }
         }
     }
 
     Destroy() {
         this.VariableGroup = null;
         this.CurrentState = null;
         this.Inbox.length = 0;
         this.StateStack.length = 0;
         this.PrioritizedInbox.length = 0;
         this.VM.DestroyFSM(this);
     }
     /**
          *
          * @param {string} title
          * @returns bool
          */
     IsListeningEvent(title) {
         return this.CurrentState.IsListeningEvent(title);
     }
 
     toString() {
         return "FSM:" + this.data.FullName;
     }
 
     ChangeState(name) {
 
         if (this.VM == null) {
             return;
         }
         if (this.data.States[name]) {
             this.CurrentState = new OBVMState(this.data.States[name], this);
             this.PostPrioritizedMessage(new OBEventMessage("Start", null, null, this));
         } else {
             throw Error("No state named " + name + " of FSM " + this.Fsmdata.Name);
         }
     }
 }
 export class OBTypedVariableGroup {
     LongRegister;
     DoubleRegister;
     StringRegister;
     StructRegister;
     NObjectRegister;
     /**
      *
      * @param {OBVariableInfo[]} variables
      */
     constructor(variables) {
         if (!variables) {
             return;
         }
         variables.forEach(v => {
             switch (v.typeIdx) {
                 case 0:
                     if (this.LongRegister != null) {
                         throw Error("duplicated type " + v.TypeIdx);
                     }
                     this.LongRegister = [];
                     break;
                 case 1:
                     if (this.DoubleRegister != null) {
                         throw Error("duplicated type " + v.TypeIdx);
                     }
                     this.DoubleRegister = [];
                     break;
                 case 2:
                     if (this.StringRegister != null) {
                         throw Error("duplicated type " + v.TypeIdx);
                     }
                     this.StringRegister = [];
                     break;
 
                 case 3:
                     if (this.StructRegister != null) {
                         throw Error("duplicated type " + v.TypeIdx);
                     }
                     this.StructRegister = [];
                     break;
                 case 4:
                     if (this.NObjectRegister != null) {
                         throw Error("duplicated type " + v.TypeIdx);
                     }
                     this.NObjectRegister = [];
                     break;
                 default:
                     throw Error("Unknown type " + v.TypeIdx);
             }
         });
     }
 }
 export class OBVMState {
     /**
      * @type {OBState}
      */
     data;
     /**
      * @type {OBVMFSM}
      */
     fsm;
     /**
      * @type {TypedVariableGroup}
      */
     VariableGroup;
     /**
      * @type {OBMessage}
      */
     currentMessage;
 
     constructor(data, fsm) {
         this.data = data;
         this.VariableGroup = new OBTypedVariableGroup(data.Variables);
         this.fsm = fsm;
     }
     /**
          *
          * @param {OBMessage} msg
          */
     HandleEvent(msg) {
         try {
             let h = this.data.EventHandlers[msg.name];
             if (h) {
                 this.currentMessage = msg;
                 new OBVMFunction(h.Func).Call(this);
             }
         } finally {
             this.currentMessage = null;
         }
     }
 
     HandleMessage(m) {
         this.currentMessage = m;
         try {
             let typeName = null;
             if (m.arg != null) {
                 typeName = m.GetArgType();
             }
             let hl = this.data.MessageHandlers[m.name];
             if (hl) {
                 hl.forEach(h => {
                     if (h.ArgTypeName == "" || h.ArgTypeName == typeName) {
                         new OBVMFunction(h.Func).Call(this);
                     }
                 });
             }
         } finally {
             this.currentMessage = null;
         }
     }
     /**
          *
          * @param {string} title
          * @returns bool
          */
     IsListeningEvent(title) {
         return !!this.data.EventHandlers[title];
     }
 
     ReceivedMessage() {
         if (this.currentMessage) {
             return this.currentMessage.arg;
         } else {
             throw Error("当前上下文没有消息可用");
         }
     }
 
     CurrentMessageSender() {
         if (this.currentMessage) {
             return this.currentMessage.sender;
         } else {
             throw Error("当前上下文没有消息可用");
         }
     }
 }
 export class OBVMFunction {
     /**
      * @type {OBFunction}
      */
     data;
     /**
      * @type {TypedVariableGroup}
      */
     LocalVar;
     returnType = -1;
     returnValue;
     /**
      *
      * @param {OBFunction} obfunc
      */
     constructor(obfunc) {
         this.data = obfunc;
         let LocalVar = new OBTypedVariableGroup(obfunc.Variables);
         this.LocalVar = LocalVar;
         LocalVar.LongRegister = [];
         LocalVar.DoubleRegister = [];
         LocalVar.StringRegister = [];
         LocalVar.StructRegister = [];
         LocalVar.NObjectRegister = [];
         for (let i = 0; i < obfunc.StringLocalVariableCount; i++) {
             LocalVar.StringRegister[i] = "";
         }
     }
     /**
          *
          * @param {OBVMState} state
          */
     Call(state) {
         let Actions = this.data.Statements.Actions;
         for (let i = 0; i < Actions.length && i >= 0;) {
             let action = Actions[i];
             i = action(state, this, this.LocalVar, i);
         }
     }
 
     SetReturnLong(v) {
         this.returnType = 1;
         this.returnValue = v;
     }
 
     Long() {
         if (this.returnType == 1) {
             return this.returnValue;
         }
         else {
             throw Error(this.data.Signure + " 没有返回 long 类型:" + this.returnType);
         }
     }
 
     SetReturnDouble(v) {
         this.returnType = 2;
         this.returnValue = v;
     }
 
     Double() {
         if (this.returnType == 2) {
             return this.returnValue;
         }
         else {
             throw Error(this.data.Signure + " 没有返回 double 类型:" + this.returnType);
         }
     }
 
     SetReturnString(v) {
         this.returnType = 3;
         this.returnValue = v;
     }
 
     String() {
         if (this.returnType == 3) {
             return this.returnValue;
         }
         else {
             throw Error(this.data.Signure + " 没有返回 string 类型:" + this.returnType);
         }
     }
 
     SetReturnStruct(v) {
         this.returnType = 4;
         this.returnValue = v;
     }
 
     Struct() {
         if (this.returnType == 4) {
             return this.returnValue;
         }
         else {
             throw Error(this.data.Signure + " 没有返回 Struct 类型:" + this.returnType);
         }
     }
 
     SetReturnNObject(v) {
         this.returnType = 5;
         this.returnValue = v;
     }
 
     NObject() {
         if (this.returnType == 5) {
             return this.returnValue;
         }
         else {
             throw Error(this.data.Signure + " 没有返回 NObject 类型:" + this.returnType);
         }
     }
 }
 export class OBMessage {
     name;
     arg;
     argType;
     sender;
     /**
      *
      * @param {string} name
      * @param {string} argType
      * @param {any} arg
      * @param {?OBVMFSM} sender
      */
     constructor(name, argType, arg, sender) {
         this.name = name;
         this.argType = argType;
         this.arg = arg;
         this.sender = sender;
     }
 
     GetArgType() {
         return this.argType;
     }
 
     static ArgTypeOf(typeId, arg) {
         switch (typeId) {
             case 0xf:
                 return "";
             case 0:
                 return "Integer";
             case 1:
                 return "Number";
             case 2:
                 return "String";
             case 3:
                 return "Struct";
             case 4:
                 // return "NObject";
                 if (arg.constructor == OBVMFSM) {
                     return "FSM";
                 } else {
                     if (arg.constructor) {
                         return arg.constructor.name;
                     } else {
                         return typeof (arg);
                     }
                 }
             default:
                 throw Error("Unknown type:" + typeId);
         }
     }
 }
 export class OBEventMessage extends OBMessage {
     /**
      *
      * @param {OBVMState} state
      */
     Handle(state) {
         try {
             state.HandleEvent(this);
         } catch (err) {
             if (!(err instanceof VMInterruptException)) {
                 console.error(err);
                 throw err;
             }
         }
     }
 }
 export class OBUserMessage extends OBMessage {
 
     /**
      *
      * @param {OBVMState} state
      */
     Handle(state) {
         try {
             state.HandleMessage(this);
         } catch (err) {
             if (!(err instanceof VMInterruptException)) {
                 console.error(err);
                 throw err;
             }
         }
     }
 }
 // 字节码
 export class STMT_start extends OBInstruction {
     StatementContext;
 
     init(code, builder, instructions, i) {
         this.StatementContext = new OBStatementContext();
         this.StatementContext.InstPos = this.Position;
     }
 
     link(builder, instructions, i) {
         if (builder.CurrentStatementStack.length > 0) {
             let Actions = null;
             builder.PushAction((st, uf, locals, pos) => {
                 if (Actions == null) {
                     Actions = this.StatementContext.Actions;
                 }
                 for (let i = 0; i < Actions.length;) {
                     let action = Actions[i];
                     i = action(st, uf, locals, i);
                 }
                 return pos + 1;
             });
         }
         builder.CurrentStatementStack.push(this.StatementContext);
     }
 }
 export class LDSTR extends OBInstruction {
     Value;
     Register;
 
     init(code, builder, instructions, i) {
         let stridx = code & 0xFFF;
         this.Value = builder.loader.data.GetString(stridx);
         this.Register = (code & 0xFFF000) >> 12;
     }
 
     link(builder, instructions, idx) {
         builder.StringRegister[this.Register] = this.getValue.bind(this);
     }
 
     getValue(UBState, obvmfunction, TypedRegisters) {
         return this.Value;
     }
 }
 export class PRT extends OBInstruction {
     RegisterType;
     RegisterIdx;
 
     init(code, builder, instructions, i) {
         this.RegisterType = (code & 0xF00000) >> 20;
         this.RegisterIdx = code & 0xFFFFF;
     }
 
     link(builder, instructions, idx) {
         let v;
         switch (this.RegisterType) {
             case 0:
                 v = builder.LongRegister[this.RegisterIdx];
                 break;
             case 1:
                 v = builder.DoubleRegister[this.RegisterIdx];
                 break;
             case 2:
                 v = builder.StringRegister[this.RegisterIdx];
                 break;
             case 3:
                 v = builder.StructRegister[this.RegisterIdx];
                 break;
             case 4:
                 v = builder.NObjectRegister[this.RegisterIdx];
                 break;
             default:
                 throw Error("Unknown type:" + this.RegisterType);
         }
         builder.PushAction((st, uf, locals, pos) => {
             //Console.WriteLine(n(st, uf));
             let val = v(st, uf, locals);
             let vm = st.fsm.VM;
             vm.Log(val);
             return ++pos;
         });
     }
 }
 export class B_STMT_end extends OBInstruction {
     link(builder, instructions, idx) {
         builder.PushAction((st, uf, locals, pos) => {
             return pos + 1;
         });
         let sc = builder.CurrentStatementStack.pop();
         if (builder.CurrentStatementStack.length == 0) {
             builder.RootStatementContext = sc;
         }
     }
 }
 export class ReceivedMessage extends OBInstruction {
     typeId;
     Register;
 
     init(code, builder, instructions, i) {
         this.typeId = (code >> 20) & 0xf;
         this.Register = code & 0xfffff;
     }
 
     link(builder, instructions, idx) {
         let Register = this.Register;
         switch (this.typeId) {
             case 0:
                 builder.LongRegister[Register] = (st, uf, locals) => {
                     return st.ReceivedMessage();
                 };
                 break;
             case 1:
                 builder.DoubleRegister[Register] = (st, uf, locals) => {
                     return st.ReceivedMessage();
                 };
                 break;
             case 2:
                 builder.StringRegister[Register] = (st, uf, locals) => {
                     return st.ReceivedMessage();
                 };
                 break;
             case 3:
                 builder.StructRegister[Register] = (st, uf, locals) => {
                     return st.ReceivedMessage();
                 };
                 break;
             case 4:
                 builder.NObjectRegister[Register] = (st, uf, locals) => {
                     return st.ReceivedMessage();
                 };
                 break;
             default:
                 throw Error("Unknown type " + this.typeId);
         }
     }
 }
 export class STVS extends OBInstruction {
     Register;
     VarIdx;
     RegisterType;
 
     init(code, builder, instructions, i) {
         this.Register = (code & 0xFF00) >> 8;
         this.RegisterType = (code & 0xFF0000) >> 16;
         this.VarIdx = code & 0xFF;
     }
 
     link(builder, instructions, idx) {
         let Register = this.Register;
         let VarIdx = this.VarIdx;
         let RegisterType = this.RegisterType;
         switch (RegisterType) {
             case 0:
                 let fl = builder.LongRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     st.VariableGroup.LongRegister[VarIdx] = fl(st, uf, locals);
                     return ++pos;
                 });
                 break;
             case 1:
                 let fd = builder.DoubleRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     st.VariableGroup.DoubleRegister[VarIdx] = fd(st, uf, locals);
                     return ++pos;
                 });
                 break;
             case 2:
                 let fs = builder.StringRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     st.VariableGroup.StringRegister[VarIdx] = fs(st, uf, locals);
                     return ++pos;
                 });
                 break;
             case 3:
                 let fst = builder.StructRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     let stt = fst(st, uf, locals);
                     st.VariableGroup.StructRegister[VarIdx] = stt;
                     if (!stt) {
                         debugger
                     }
                     return ++pos;
                 });
                 break;
             case 4:
                 let fo = builder.NObjectRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     st.VariableGroup.NObjectRegister[VarIdx] = fo(st, uf, locals);
                     return ++pos;
                 });
                 break;
             default:
                 throw Error("Unknown type " + RegisterType);
         }
     }
 }
 export class STVG extends OBInstruction {
     Register;
     VarIdx;
     RegisterType;
 
     init(code, builder, instructions, i) {
         this.Register = (code & 0xFF00) >> 8;
         this.RegisterType = (code & 0xFF0000) >> 16;
         this.VarIdx = code & 0xFF;
     }
 
     link(builder, instructions, idx) {
         let Register = this.Register;
         let VarIdx = this.VarIdx;
         switch (this.RegisterType) {
             case 0:
                 builder.LongRegister[Register] = (st, uf, locals) => {
                     return st.VariableGroup.LongRegister[VarIdx];
                 };
                 break;
             case 1:
                 builder.DoubleRegister[Register] = (st, uf, locals) => {
                     return st.VariableGroup.DoubleRegister[VarIdx];
                 };
                 break;
             case 2:
                 builder.StringRegister[Register] = (st, uf, locals) => {
                     return st.VariableGroup.StringRegister[VarIdx];
                 };
                 break;
             case 3:
                 builder.StructRegister[Register] = (st, uf, locals) => {
                     return st.VariableGroup.StructRegister[VarIdx];
                 };
                 break;
             case 4:
                 builder.NObjectRegister[Register] = (st, uf, locals) => {
                     return st.VariableGroup.NObjectRegister[VarIdx];
                 };
                 break;
             default:
                 throw Error("Unknown type " + this.RegisterType);
         }
     }
 }
 export class StructFieldDesc extends OBInstruction {
     fieldTypeId;
     fieldDescIdx;
 
     init(code, builder, instructions, i) {
         this.fieldDescIdx = code & 0xfffff;
         this.fieldTypeId = (code >> 20) & 0xf;
     }
 }
 export class GetStructField extends OBInstruction {
     structIdx;
     Register;
     typeId;
     fieldIdx;
 
     init(code, builder, instructions, i) {
         let desc = instructions[i - 1];
         if (!(desc instanceof StructFieldDesc)) {
             throw Error("last cmd is not StructFieldDesc");
         }
         this.structIdx = (code >> 12) & 0xfff;
         this.Register = (code) & 0xfff;
         this.typeId = desc.fieldTypeId;
         this.fieldIdx = desc.fieldDescIdx;
     }
 
     link(builder, instructions, idx) {
         let Register = this.Register;
         let fieldIdx = this.fieldIdx;
         let getStruct = builder.StructRegister[this.structIdx];
         switch (this.typeId) {
 
             case 0:
                 builder.LongRegister[Register] = (st, uf, locals) => {
                     let stt = getStruct(st, uf, locals);
                     return stt.registers.LongRegister[fieldIdx];
                 };
                 break;
             case 1:
                 builder.DoubleRegister[Register] = (st, uf, locals) => {
                     return getStruct(st, uf, locals).registers.DoubleRegister[fieldIdx];
                 };
                 break;
             case 2:
                 builder.StringRegister[Register] = (st, uf, locals) => {
                     return getStruct(st, uf, locals).registers.StringRegister[fieldIdx];
                 };
                 break;
             case 3:
                 builder.StructRegister[Register] = (st, uf, locals) => {
                     return getStruct(st, uf, locals).registers.StructRegister[fieldIdx];
                 };
                 break;
             case 4:
                 builder.NObjectRegister[Register] = (st, uf, locals) => {
                     return getStruct(st, uf, locals).registers.NObjectRegister[fieldIdx];
                 };
                 break;
             default:
                 throw Error("Unknown type " + this.typeId);
         }
 
     }
 }
 export class SetStructField extends OBInstruction {
     structIdx;
     Register;
     typeId;
     fieldIdx;
 
     init(code, builder, instructions, i) {
         let desc = instructions[i - 1];
         if (!(desc instanceof StructFieldDesc)) {
             throw Error("last cmd is not StructFieldDesc");
         }
         this.structIdx = (code >> 12) & 0xfff;
         this.Register = (code) & 0xfff;
         this.typeId = desc.fieldTypeId;
         this.fieldIdx = desc.fieldDescIdx;
     }
 
     link(builder, instructions, idx) {
         let Register = this.Register;
         let fieldIdx = this.fieldIdx;
         let getStruct = builder.StructRegister[this.structIdx];
         switch (this.typeId) {
             case 0:
                 let getLong = builder.LongRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     getStruct(st, uf, locals).registers.LongRegister[fieldIdx] = getLong(st, uf, locals);
                     return ++pos;
                 });
                 break;
             case 1:
                 let getDouble = builder.DoubleRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     getStruct(st, uf, locals).registers.DoubleRegister[fieldIdx] = getDouble(st, uf, locals);
                     return ++pos;
                 });
                 break;
             case 2:
                 let GetString = builder.StringRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     getStruct(st, uf, locals).registers.StringRegister[fieldIdx] = GetString(st, uf, locals);
                     return ++pos;
                 });
                 break;
             case 3:
                 let getStruct1 = builder.StructRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     getStruct(st, uf, locals).registers.StructRegister[fieldIdx] = getStruct1(st, uf, locals);
                     return ++pos;
                 });
                 break;
             case 4:
                 let getNObject = builder.NObjectRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     getStruct(st, uf, locals).registers.NObjectRegister[fieldIdx] = getNObject(st, uf, locals);
                     return ++pos;
                 });
                 break;
             default:
                 throw Error("Unknown type " + this.typeId);
         }
 
     }
 }
 export class CHSTT extends OBInstruction {
     StateName;
 
     init(code, builder, instructions, i) {
         let strIdx = (code & 0xFFFFFF);
         let str = builder.loader.data.GetString(strIdx);
         this.StateName = str;
     }
 
     link(builder, instructions, idx) {
         builder.PushAction((state, uf, locals, pos) => {
             state.fsm.ChangeState(this.StateName);
             throw new ChangeStateException();
             //return ++pos;
         });
     }
 }
 export class MethodCallRegisterInfoAnchor extends OBInstruction {
     RegisterInfoIdx;
 
     init(code, builder, instructions, i) {
         this.RegisterInfoIdx = code & 0xFFFF;
     }
 }
 export class NativeMethodCall extends OBInstruction {
     LibNameIdx;
 
     init(code, builder, instructions, i) {
         this.LibNameIdx = code & 0xFFFFFF;
     }
 
     link(builder, instructions, idx) {
         let LibName = builder.loader.data.GetString(this.LibNameIdx);
         let anchor = instructions[idx - 1];
         if (!(anchor instanceof MethodCallRegisterInfoAnchor)) {
             throw Error("last cmd is not MethodCallRegisterInfoAnchor");
         }
         let RegisterInfoIdx = anchor.RegisterInfoIdx;
         let args = builder.loader.data.GetInt32FromBin(RegisterInfoIdx);
         let funcIdx = args[0];
         let _args = args.slice(1);
         let installer = builder.loader.script.getNativeFunc(LibName, funcIdx);
         installer(builder, _args);
     }
 }
 export class FSMVS extends OBInstruction {
     Register;
     VarIdx;
     RegisterType;
 
     init(code, builder, instructions, i) {
         this.Register = (code & 0xFF00) >> 8;
         this.RegisterType = (code & 0xFF0000) >> 16;
         this.VarIdx = code & 0xFF;
     }
 
     link(builder, instructions, idx) {
         let Register = this.Register;
         let VarIdx = this.VarIdx;
         let RegisterType = this.RegisterType;
         switch (RegisterType) {
             case 0:
                 let fl = builder.LongRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     st.fsm.VariableGroup.LongRegister[VarIdx] = fl(st, uf, locals);
                     return ++pos;
                 });
                 break;
             case 1:
                 let fd = builder.DoubleRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     st.fsm.VariableGroup.DoubleRegister[VarIdx] = fd(st, uf, locals);
                     return ++pos;
                 });
                 break;
             case 2:
                 let fs = builder.StringRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     st.fsm.VariableGroup.StringRegister[VarIdx] = fs(st, uf, locals);
                     return ++pos;
                 });
                 break;
             case 3:
                 let fst = builder.StructRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     st.fsm.VariableGroup.StructRegister[VarIdx] = fst(st, uf, locals);
                     return ++pos;
                 });
                 break;
             case 4:
                 let fo = builder.NObjectRegister[Register];
                 builder.PushAction((st, uf, locals, pos) => {
                     st.fsm.VariableGroup.NObjectRegister[VarIdx] = fo(st, uf, locals);
                     return ++pos;
                 });
                 break;
             default:
                 throw Error("Unknown type " + RegisterType);
         }
     }
 }
 export class SLF extends OBInstruction {
     RegisterIdx;
 
     init(code, builder, instructions, i) {
         this.RegisterIdx = code & 0xffffff;
     }
 
     link(builder, instructions, idx) {
         builder.NObjectRegister[this.RegisterIdx] = (s, f, l) => {
             return s.fsm;
         };
     }
 }
 export class MethodCall extends OBInstruction {
     MethodNameIdx;
 
     init(code, builder, instructions, i) {
         this.MethodNameIdx = code & 0xFFFFFF;
     }
 
     link(builder, instructions, idx) {
         let MethodName = builder.loader.data.GetString(this.MethodNameIdx);
         let anchor = instructions[idx - 1];
         if (!(anchor instanceof MethodCallRegisterInfoAnchor)) {
             throw Error("last cmd is not MethodCallRegisterInfoAnchor");
         }
         let RegisterInfoIdx = anchor.RegisterInfoIdx;
         let args = builder.loader.data.GetInt32FromBin(RegisterInfoIdx);
 
         let uf1 = builder.loader.script.loadedFunctions[MethodName];
         if (uf1 != null) {
             // 参数
             let f = new OBVMFunction(uf1, builder, args);
             let returnRegister = args[0];
             if (returnRegister == -1) {
                 builder.PushAction((state, uf, localVars, pos) => {
                     f.Call(state, f, localVars);
                     return ++pos;
                 });
             } else {
                 let Register = returnRegister & 0xFFF;
                 let registerType = (returnRegister >> 12) & 0xF;
                 // 处理有返回值的情况
                 switch (registerType) {
                     case 0:
                         builder.LongRegister[Register] = (st, uf, l) => {
                             f.Call(st, uf, l);
                             return f.Long();
                         };
                         break;
                     case 1:
                         builder.DoubleRegister[Register] = (st, uf, l) => {
                             f.Call(st, uf, l);
                             return f.Double();
                         };
                         break;
                     case 2:
                         builder.StringRegister[Register] = (st, uf, l) => {
                             f.Call(st, uf, l);
                             return f.String();
                         };
                         break;
                     case 3:
                         builder.StructRegister[Register] = (st, uf, l) => {
                             f.Call(st, uf, l);
                             return f.Struct();
                         };
                         break;
                     case 4:
                         builder.NObjectRegister[Register] = (st, uf, l) => {
                             f.Call(st, uf, l);
                             return f.NObject();
                         };
                         break;
                     default:
                         throw Error("Unknown type " + registerType);
                 }
             }
         } else {
             throw Error("未找到函数 " + MethodName);
         }
     }
 }
 export class BRIFN extends OBInstruction {
     checkRegType;
     checkRegIdx;
     targetOffset;
 
     init(code, builder, instructions, i) {
         this.checkRegType = ((code >> 20) & 0xf);
         this.checkRegIdx = ((code >> 14) & 0x7f);
         this.targetOffset = (((code & 0x1fff) << 19) >> 19); //;// ((code) & 0x1fff);
         builder.PositionUpdate(this.targetOffset * 4, (newPos) => {
             this.targetOffset = newPos;
         });
     }
 
     link(builder, instructions, idx) {
         let checkRegType = this.checkRegType;
         let checkRegIdx = this.checkRegIdx;
         switch (checkRegType) {
             case 0:
                 let LongReg = builder.LongRegister[checkRegIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     if (LongReg(st, uf, locals) == 0) {
                         return this.targetOffset;
                     } else {
                         return ++pos;
                     }
                 });
                 break;
             case 1:
                 let DoubleReg = builder.DoubleRegister[checkRegIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     if (DoubleReg(st, uf, locals) == 0) {
                         return this.targetOffset;
                     } else {
                         return ++pos;
                     }
                 });
                 break;
             case 2:
                 let StringReg = builder.StringRegister[checkRegIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     let str = StringReg(st, uf, locals);
                     if (str == null || ("" == (str))) {
                         return this.targetOffset;
                     } else {
                         return ++pos;
                     }
                 });
                 break;
             case 3:
                 let StructReg = builder.StructRegister[checkRegIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     if (StructReg(st, uf, locals) == null) {
                         return this.targetOffset;
                     } else {
                         return ++pos;
                     }
                 });
                 break;
             case 4:
                 let NObjectReg = builder.NObjectRegister[checkRegIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     if (NObjectReg(st, uf, locals) == null) {
                         return this.targetOffset;
                     } else {
                         return ++pos;
                     }
                 });
                 break;
             default:
                 throw Error("Unknown type " + checkRegType);
         }
     }
 }
 export class BR extends OBInstruction {
     Offset;
 
     init(code, builder, instructions, i) {
         this.Offset = ((code << 8) >> 8);
         builder.PositionUpdate(this.Offset * 4, (newPos) => {
             this.Offset = newPos;
         });
     }
 
     link(builder, instructions, idx) {
         builder.PushAction((ub, uf, locals, pos) => {
             return this.Offset;
         });
     }
 }
 export class NOP extends OBInstruction {
     link(builder, instructions, idx) {
         builder.PushAction((st, uf, locals, pos) => {
             return pos + 1;
         });
     }
 }
 export class ARITHF extends OBInstruction {
     Opcode;
     LeftRegister;
     RightRegister;
 
     init(code, builder, instructions, i) {
         this.LeftRegister = (code >> 10) & 0x3FF;
         this.RightRegister = (code & 0x3FF);
         this.Opcode = (code >> 20) & 0xf;
     }
 
     link(builder, instructions, idx) {
         let left = builder.DoubleRegister[this.LeftRegister];
         let right = builder.DoubleRegister[this.RightRegister];
         if (left == null) {
             throw Error("left is null");
         }
         if (right == null) {
             throw Error("right is null");
         }
         let o;
         switch (this.Opcode) {
             case 0:
                 o = (st, f, locals) => {
                     var l = left(st, f, locals);
                     var r = right(st, f, locals);
                     return l + r;
                 }
                 break;
             case 1:
                 o = (st, f, locals) => {
                     var l = left(st, f, locals);
                     var r = right(st, f, locals);
                     return l - r;
                 }
                 break;
             case 2:
                 o = (st, f, locals) => {
                     var l = left(st, f, locals);
                     var r = right(st, f, locals);
                     return l * r;
                 }
                 break;
             case 3:
                 o = (st, f, locals) => {
                     var l = left(st, f, locals);
                     var r = right(st, f, locals);
                     return l / r;
                 }
                 break;
             case 4:
                 o = (st, f, locals) => {
                     var l = left(st, f, locals);
                     var r = right(st, f, locals);
                     return Math.pow(l, r);
                 }
                 break;
             case 5:
                 o = (st, f, locals) => {
                     var l = left(st, f, locals);
                     var r = right(st, f, locals);
                     return l % r;
                 }
                 break;
             default:
                 throw Error("未知操作符 " + this.Opcode);
         }
         builder.DoubleRegister[this.LeftRegister] = o;
     }
 }
 
 export class ARITHI extends OBInstruction {
     Opcode;
     LeftRegister;
     RightRegister;
 
     init(code, builder, instructions, i) {
         this.LeftRegister = (code >> 10) & 0x3FF;
         this.RightRegister = (code & 0x3FF);
         this.Opcode = (code >> 20) & 0xf;
     }
 
     link(builder, instructions, idx) {
         let left = builder.LongRegister[this.LeftRegister];
         let right = builder.LongRegister[this.RightRegister];
         if (left == null) {
             throw Error("left is null");
         }
         if (right == null) {
             throw Error("right is null");
         }
         let o;
         switch (this.Opcode) {
             case 0:
                 o = (st, f, locals) => {
                     var l = left(st, f, locals);
                     var r = right(st, f, locals);
                     return l + r;
                 }
                 break;
             case 1:
                 o = (st, f, locals) => {
                     var l = left(st, f, locals);
                     var r = right(st, f, locals);
                     return l - r;
                 }
                 break;
             case 2:
                 o = (st, f, locals) => {
                     var l = left(st, f, locals);
                     var r = right(st, f, locals);
                     return l * r;
                 }
                 break;
             case 3:
                 o = (st, f, locals) => {
                     var l = left(st, f, locals);
                     var r = right(st, f, locals);
                     return Math.floor(l / r);
                 }
                 break;
             case 4:
                 o = (st, f, locals) => {
                     var l = left(st, f, locals);
                     var r = right(st, f, locals);
                     return Math.floor(Math.pow(l, r));
                 }
                 break;
             case 5:
                 o = (st, f, locals) => {
                     var l = left(st, f, locals);
                     var r = right(st, f, locals);
                     return l % r;
                 }
                 break;
             default:
                 throw Error("未知操作符 " + this.Opcode);
         }
         builder.LongRegister[this.LeftRegister] = o;
     }
 }
 export class LDI extends OBInstruction {
     Register;
     Value;
 
     init(code, builder, instructions, i) {
         let pos = code & 0xFFF;
         this.Value = builder.loader.data.getInt32(pos * 4); // 4字节对齐
         this.Register = ((code & 0xFFF000) >> 12);
     }
 
     link(builder, instructions, idx) {
         builder.LongRegister[this.Register] = () => {
             return this.Value;
         };
     }
 }
 export class LDF extends OBInstruction {
     Register;
     Value;
 
     init(code, builder, instructions, i) {
         let specal = code & 0xFFF;
         switch (specal) {
             case 0xFFE:
                 this.Value = Number.POSITIVE_INFINITY;
                 break;
             case 0xFFD:
                 this.Value = Number.NEGATIVE_INFINITY;
                 break;
             case 0xFFF:
                 this.Value = Number.NaN;
                 break;
             default:
                 this.Value = builder.loader.data.getFloat(specal * 4);
                 break;
         }
         this.Register = ((code & 0xFFF000) >> 12);
     }
 
     link(builder, instructions, idx) {
         builder.DoubleRegister[this.Register] = () => {
             return this.Value;
         };
     }
 }
 export class RET extends OBInstruction {
     RegisterType;
     RegisterIdx;
 
     init(code, builder, instructions, i) {
         this.RegisterType = ((code & 0xF00000) >> 20);
         this.RegisterIdx = (code & 0xFFFFF);
     }
 
     link(builder, instructions, idx) {
         switch (this.RegisterType) {
             case 0:
                 let l = builder.LongRegister[this.RegisterIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     let v = l(st, uf, locals);
                     uf.SetReturnLong(v);
                     return -1;
                 });
                 break;
             case 1:
                 let f = builder.DoubleRegister[this.RegisterIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     let v = f(st, uf, locals);
                     uf.SetReturnDouble(v);
                     return -1;
                 });
                 break;
             case 2:
                 let s = builder.StringRegister[this.RegisterIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     //Console.WriteLine(s(st, uf));
                     let v = s(st, uf, locals);
                     uf.SetReturnString(v);
                     return -1;
                 });
                 break;
             case 3:
                 let u = builder.StructRegister[this.RegisterIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     //Console.WriteLine(u(st, uf));
                     let v = u(st, uf, locals);
                     uf.SetReturnStruct(v);
                     return -1;
                 });
                 break;
             case 4:
                 let n = builder.NObjectRegister[this.RegisterIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     //Console.WriteLine(n(st, uf));
                     let v = n(st, uf, locals);
                     uf.SetReturnNObject(v);
                     return -1;
                 });
                 break;
             case 0xf:
                 builder.PushAction((st, uf, locals, pos) => {
                     return -1;
                 });
                 break;
             default:
                 throw Error("Unknown type:" + this.RegisterType);
         }
     }
 }
 export class FSMVG extends OBInstruction {
     Register;
     VarIdx;
     RegisterType;
 
     init(code, builder, instructions, i) {
         this.Register = (code & 0xFF00) >> 8;
         this.RegisterType = (code & 0xFF0000) >> 16;
         this.VarIdx = code & 0xFF;
     }
 
     link(builder, instructions, idx) {
         let VarIdx = this.VarIdx;
         let Register = this.Register;
         switch (this.RegisterType) {
             case 0:
                 builder.LongRegister[Register] = (st, uf, l) => {
                     return st.fsm.VariableGroup.LongRegister[VarIdx];
                 };
                 break;
             case 1:
                 builder.DoubleRegister[Register] = (st, uf, l) => {
                     return st.fsm.VariableGroup.DoubleRegister[VarIdx];
                 };
                 break;
             case 2:
                 builder.StringRegister[Register] = (st, uf, l) => {
                     return st.fsm.VariableGroup.StringRegister[VarIdx];
                 };
                 break;
             case 3:
                 builder.StructRegister[Register] = (st, uf, l) => {
                     return st.fsm.VariableGroup.StructRegister[VarIdx];
                 };
                 break;
             case 4:
                 builder.NObjectRegister[Register] = (st, uf, l) => {
                     return st.fsm.VariableGroup.NObjectRegister[VarIdx];
                 };
                 break;
             default:
                 throw Error("Unknown type " + this.RegisterType);
         }
     }
 }
 export class CreateFSM extends OBInstruction {
     FSMTypeName;
     ReturnRegister;
 
     init(code, builder, instructions, i) {
         let FSMTypeNameIdx = code & 0xFFFF;
         this.FSMTypeName = builder.loader.data.GetString(FSMTypeNameIdx);
         this.ReturnRegister = (code & 0xFF0000) >> 16;
     }
 
     link(builder, instructions, idx) {
         builder.NObjectRegister[this.ReturnRegister] = (st, fun, l) => {
             let fsm = st.fsm.VM.CreateFSM(this.FSMTypeName);
             if (!fsm) {
                 st.fsm.VM.Log("未找到FSM类型 " + this.FSMTypeName);
             }
             return fsm;
         };
     }
 }
 export class FSMSendMsg extends OBInstruction {
     TitleIdx;
     TargetIdx;
     BodyTypeID;
     BodyRegisterIdx;
 
     init(code, builder, instructions, i) {
         this.TargetIdx = ((code >> 17) & 0x7F);
         this.TitleIdx = ((code >> 10) & 0x7F);
         this.BodyTypeID = ((code >> 6) & 0xF);
 
         this.BodyRegisterIdx = (code & 0x3F);
     }
     /**
          *
          * @param {OBFunctionBuilder} builder
          * @param {*} instructions
          * @param {*} idx
          */
     link(builder, instructions, idx) {
         let f_title = builder.StringRegister[this.TitleIdx];
         let f_body = this.makeBody(builder);
         let f_fsm = builder.NObjectRegister[this.TargetIdx];
         builder.PushAction((st, uf, locals, pos) => {
             let fsm = f_fsm(st, uf, locals);
             if (fsm) {
                 let title = f_title(st, uf, locals);
                 let body = f_body(st, uf, locals);
                 fsm.PostMessage(new OBUserMessage(title, OBMessage.ArgTypeOf(this.BodyTypeID, body), body, st.fsm));
             }
             return ++pos;
         });
     }
     /**
          *
          * @param {OBFunctionBuilder} builder
          * @returns
          */
     makeBody(builder) {
         let BodyRegisterIdx = this.BodyRegisterIdx;
         switch (this.BodyTypeID) {
             case 0xF:
                 return (st, uf, locals) => null;
             case 0:
                 var l = builder.LongRegister[BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return l(st, uf, locals);
                 };
             case 1:
                 var d = builder.DoubleRegister[BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return d(st, uf, locals);
                 };
             case 2:
                 var s = builder.StringRegister[BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return s(st, uf, locals);
                 };
             case 3:
                 var s1 = builder.StructRegister[BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return s1(st, uf, locals);
                 };
             case 4:
                 var n = builder.NObjectRegister[BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return n(st, uf, locals);
                 };
             default:
                 throw Error("Unknown type " + this.BodyTypeID);
         }
     }
 }
 export class GZ0 extends OBInstruction {
     VarType;
     VarIdx;
     ResultIdx;
 
     init(code, builder, instructions, i) {
         this.VarType = ((code >> 20) & 0xf);
         this.VarIdx = ((code >> 10) & 0x3ff);
         this.ResultIdx = (code & 0x3ff);
     }
 
     link(builder, instructions, idx) {
         let ResultIdx = this.ResultIdx;
         let VarIdx = this.VarIdx;
         switch (this.VarType) {
             case 0:
                 let getLong = builder.LongRegister[VarIdx];
                 builder.LongRegister[ResultIdx] = (st, uf, locals) => {
                     let lv = getLong(st, uf, locals);
                     return lv > 0 ? 1 : 0;
                 };
                 break;
             case 1:
                 let getDouble = builder.DoubleRegister[VarIdx];
                 builder.LongRegister[ResultIdx] = (st, uf, locals) => {
                     return getDouble(st, uf, locals) > 0 ? 1 : 0;
                 };
                 break;
             case 2:
                 let GetString = builder.StringRegister[VarIdx];
                 builder.LongRegister[ResultIdx] = (st, uf, locals) => {
                     return GetString(st, uf, locals) != null ? 1 : 0;
                 };
                 break;
             case 3:
                 let getStruct = builder.StructRegister[VarIdx];
                 builder.LongRegister[ResultIdx] = (st, uf, locals) => {
                     return getStruct(st, uf, locals) != null ? 1 : 0;
                 };
                 break;
             case 4:
                 let getNObject = builder.NObjectRegister[VarIdx];
                 builder.LongRegister[ResultIdx] = (st, uf, locals) => {
                     return getNObject(st, uf, locals) == null ? 1 : 0;
                 };
                 break;
             default:
                 throw Error("Unknown type " + this.VarType);
         }
     }
 }
 
 export class BRIF extends OBInstruction {
     checkRegType;
     checkRegIdx;
     targetOffset;
 
     init(code, builder, instructions, i) {
         this.checkRegType = ((code >> 20) & 0xf);
         this.checkRegIdx = ((code >> 14) & 0x7f);
         this.targetOffset = (((code & 0x1fff) << 19) >> 19); //;// ((code) & 0x1fff);
         builder.PositionUpdate(this.targetOffset * 4, (newPos) => {
             this.targetOffset = newPos;
         });
     }
 
     link(builder, instructions, idx) {
         let checkRegType = this.checkRegType;
         let checkRegIdx = this.checkRegIdx;
         switch (checkRegType) {
             case 0:
                 let LongReg = builder.LongRegister[checkRegIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     if (LongReg(st, uf, locals) != 0) {
                         return this.targetOffset;
                     } else {
                         return ++pos;
                     }
                 });
                 break;
             case 1:
                 let DoubleReg = builder.DoubleRegister[checkRegIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     if (DoubleReg(st, uf, locals) != 0) {
                         return this.targetOffset;
                     } else {
                         return ++pos;
                     }
                 });
                 break;
             case 2:
                 let StringReg = builder.StringRegister[checkRegIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     let str = StringReg(st, uf, locals);
                     if (str != null && !("" == (str))) {
                         return this.targetOffset;
                     } else {
                         return ++pos;
                     }
                 });
                 break;
             case 3:
                 let StructReg = builder.StructRegister[checkRegIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     if (StructReg(st, uf, locals) != null) {
                         return this.targetOffset;
                     } else {
                         return ++pos;
                     }
                 });
                 break;
             case 4:
                 let NObjectReg = builder.NObjectRegister[checkRegIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     if (NObjectReg(st, uf, locals) != null) {
                         return this.targetOffset;
                     } else {
                         return ++pos;
                     }
                 });
                 break;
             default:
                 throw Error("Unknown type " + this.checkRegType);
         }
     }
 }
 export class DEC extends OBInstruction {
     regType;
     regIdx;
 
     init(code, builder, instructions, i) {
         this.regType = ((code >> 20) & 0xf);
         this.regIdx = ((code) & 0xfffff);
     }
 
     link(builder, instructions, idx) {
         let regIdx = this.regIdx;
         let enable = true;
         switch (this.regType) {
             case 0:
                 let LongReg = builder.LongRegister[regIdx];
                 builder.LongRegister[regIdx] = (st, uf, locals) => {
                     if (enable) {
                         enable = false;
                         let v = LongReg(st, uf, locals);
                         return v - 1;
                     } else {
                         throw Error("reentry");
                     }
                 };
                 break;
             case 1:
                 let DoubleReg = builder.DoubleRegister[regIdx];
                 builder.DoubleRegister[regIdx] = (st, uf, locals) => {
                     if (enable) {
                         enable = false;
                         let v = DoubleReg(st, uf, locals);
                         return v - 1;
                     } else {
                         throw Error("reentry");
                     }
                 };
                 break;
             case 2:
             case 3:
             case 4:
             default:
                 throw Error("Unsupport type " + this.regType);
         }
     }
 }
 export class Reg2Var extends OBInstruction {
     type;
     varIdx;
     regIdx;
 
     init(code, builder, instructions, i) {
         this.type = ((code >> 20) & 0xf);
         this.regIdx = ((code >> 10) & 0x3ff);
         this.varIdx = ((code) & 0x3ff);
     }
 
     link(builder, instructions, idx) {
         let varIdx = this.varIdx;
         let regIdx = this.regIdx;
         switch (this.type) {
             case 0:
                 let getLong = builder.LongRegister[regIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     locals.LongRegister[varIdx] = getLong(st, uf, locals);
                     return 1 + pos;
                 });
                 break;
             case 1:
                 let getDouble = builder.DoubleRegister[regIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     locals.DoubleRegister[varIdx] = getDouble(st, uf, locals);
                     return 1 + pos;
                 });
                 break;
             case 2:
                 let GetString = builder.StringRegister[regIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     locals.StringRegister[varIdx] = GetString(st, uf, locals);
                     return 1 + pos;
                 });
                 break;
             case 3:
                 let getStruct = builder.StructRegister[regIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     locals.StructRegister[varIdx] = getStruct(st, uf, locals);
                     return 1 + pos;
                 });
                 break;
             case 4:
                 let getNObject = builder.NObjectRegister[regIdx];
                 builder.PushAction((st, uf, locals, pos) => {
                     locals.NObjectRegister[varIdx] = getNObject(st, uf, locals);
                     return 1 + pos;
                 });
                 break;
             default:
                 throw Error("Unsupport type:" + this.type);
         }
     }
 }
 export class Var2Reg extends OBInstruction {
     type;
     varIdx;
     regIdx;
 
     init(code, builder, instructions, i) {
         this.type = ((code >> 20) & 0xf);
         this.regIdx = ((code >> 10) & 0x3ff);
         this.varIdx = ((code) & 0x3ff);
     }
 
     link(builder, instructions, idx) {
         let varIdx = this.varIdx;
         let regIdx = this.regIdx;
         switch (this.type) {
             case 0:
                 builder.LongRegister[regIdx] = (st, uf, locals) => {
                     return locals.LongRegister[varIdx];
                 };
                 break;
             case 1:
                 builder.DoubleRegister[regIdx] = (st, uf, locals) => {
                     return locals.DoubleRegister[varIdx];
                 };
                 break;
             case 2:
                 builder.StringRegister[regIdx] = (st, uf, locals) => {
                     return locals.StringRegister[varIdx];
                 };
                 break;
             case 3:
                 builder.StructRegister[regIdx] = (st, uf, locals) => {
                     return locals.StructRegister[varIdx];
                 };
                 break;
             case 4:
                 builder.NObjectRegister[regIdx] = (st, uf, locals) => {
                     return locals.NObjectRegister[varIdx];
                 };
                 break;
             default:
                 throw Error("Unsupport type:" + this.type);
         }
     }
 }
 export class I2F extends OBInstruction {
     intRegIdx;
     floatRegIdx;
 
     init(code, builder, instructions, i) {
         this.intRegIdx = ((code) >> 12) & 0xFFF;
         this.floatRegIdx = ((code) & 0xFFF);
     }
 
     link(builder, instructions, idx) {
         let getLong = builder.LongRegister[this.intRegIdx];
         builder.DoubleRegister[this.floatRegIdx] = (st, uf, locals) => {
             return getLong(st, uf, locals);
         };
     }
 }
 export class EQ extends OBInstruction {
     ArgTypeId;
     LeftIdx;
     RightIdx;
     RetIdx;
 
     init(code, builder, instructions, i) {
         this.ArgTypeId = (code >> 20) & 0xF;
         this.LeftIdx = (code >> 14) & 0x3f;
         this.RightIdx = (code >> 7) & 0x7f;
         this.RetIdx = code & 0x7f;
     }
     /**
          *
          * @param {OBFunctionBuilder} builder
          * @param {*} instructions
          * @param {*} idx
          */
     link(builder, instructions, idx) {
         let regArr;
         switch (this.ArgTypeId) {
             case 0:
                 regArr = builder.LongRegister;
                 break;
             case 1:
                 regArr = builder.DoubleRegister;
                 break;
             case 2:
                 regArr = builder.StringRegister;
                 break;
             case 3:
                 regArr = builder.StructRegister;
                 break;
             case 4:
                 regArr = builder.NObjectRegister;
                 ;
                 break;
             default:
                 throw Error("不支持类型：" + this.ArgTypeId);
         }
         let LeftReg = regArr[this.LeftIdx];
         let RightReg = regArr[this.RightIdx];
         builder.LongRegister[this.RetIdx] = (st, uf, locals) => {
             return LeftReg(st, uf, locals) == RightReg(st, uf, locals) ? 1 : 0;
         };
     }
 }
 export class NEQ extends OBInstruction {
     ArgTypeId;
     LeftIdx;
     RightIdx;
     RetIdx;
 
     init(code, builder, instructions, i) {
         this.ArgTypeId = (code >> 20) & 0xF;
         this.LeftIdx = (code >> 14) & 0x3f;
         this.RightIdx = (code >> 7) & 0x7f;
         this.RetIdx = code & 0x7f;
     }
     /**
          *
          * @param {OBFunctionBuilder} builder
          * @param {*} instructions
          * @param {*} idx
          */
     link(builder, instructions, idx) {
         let regArr;
         switch (this.ArgTypeId) {
             case 0:
                 regArr = builder.LongRegister;
                 break;
             case 1:
                 regArr = builder.DoubleRegister;
                 break;
             case 2:
                 regArr = builder.StringRegister;
                 break;
             case 3:
                 regArr = builder.StructRegister;
                 break;
             case 4:
                 regArr = builder.NObjectRegister;
                 ;
                 break;
             default:
                 throw Error("不支持类型：" + this.ArgTypeId);
         }
         let LeftReg = regArr[this.LeftIdx];
         let RightReg = regArr[this.RightIdx];
         builder.LongRegister[this.RetIdx] = (st, uf, locals) => {
             return LeftReg(st, uf, locals) != RightReg(st, uf, locals) ? 1 : 0;
         };
     }
 }
 export class LT extends OBInstruction {
     ArgTypeId;
     LeftIdx;
     RightIdx;
     RetIdx;
 
     init(code, builder, instructions, i) {
         this.ArgTypeId = (code >> 20) & 0xF;
         this.LeftIdx = (code >> 14) & 0x3f;
         this.RightIdx = (code >> 7) & 0x7f;
         this.RetIdx = code & 0x7f;
     }
 
     link(builder, instructions, idx) {
         let regArr;
         switch (this.ArgTypeId) {
             case 0:
                 regArr = builder.LongRegister;
                 break;
             case 1:
                 regArr = builder.DoubleRegister;
                 break;
             case 2:
                 regArr = builder.StringRegister;
                 return;
             default:
                 throw Error("不支持类型：" + this.ArgTypeId);
         }
         let LeftReg = regArr[this.LeftIdx];
         let RightReg = regArr[this.RightIdx];
         builder.LongRegister[this.RetIdx] = (st, uf, locals) => {
             return LeftReg(st, uf, locals) < RightReg(st, uf, locals) ? 1 : 0;
         };
     }
 }
 export class LTE extends OBInstruction {
     ArgTypeId;
     LeftIdx;
     RightIdx;
     RetIdx;
 
     init(code, builder, instructions, i) {
         this.ArgTypeId = (code >> 20) & 0xF;
         this.LeftIdx = (code >> 14) & 0x3f;
         this.RightIdx = (code >> 7) & 0x7f;
         this.RetIdx = code & 0x7f;
     }
 
     link(builder, instructions, idx) {
         let regArr;
         switch (this.ArgTypeId) {
             case 0:
                 regArr = builder.LongRegister;
                 break;
             case 1:
                 regArr = builder.DoubleRegister;
                 break;
             case 2:
                 regArr = builder.StringRegister;
                 return;
             default:
                 throw Error("不支持类型：" + this.ArgTypeId);
         }
         let LeftReg = regArr[this.LeftIdx];
         let RightReg = regArr[this.RightIdx];
         builder.LongRegister[this.RetIdx] = (st, uf, locals) => {
             return LeftReg(st, uf, locals) <= RightReg(st, uf, locals) ? 1 : 0;
         };
     }
 }
 export class GT extends OBInstruction {
     ArgTypeId;
     LeftIdx;
     RightIdx;
     RetIdx;
 
     init(code, builder, instructions, i) {
         this.ArgTypeId = (code >> 20) & 0xF;
         this.LeftIdx = (code >> 14) & 0x3f;
         this.RightIdx = (code >> 7) & 0x7f;
         this.RetIdx = code & 0x7f;
     }
 
     link(builder, instructions, idx) {
         let regArr;
         switch (this.ArgTypeId) {
             case 0:
                 regArr = builder.LongRegister;
                 break;
             case 1:
                 regArr = builder.DoubleRegister;
                 break;
             case 2:
                 regArr = builder.StringRegister;
                 return;
             default:
                 throw Error("不支持类型：" + this.ArgTypeId);
         }
         let LeftReg = regArr[this.LeftIdx];
         let RightReg = regArr[this.RightIdx];
         builder.LongRegister[this.RetIdx] = (st, uf, locals) => {
             return LeftReg(st, uf, locals) > RightReg(st, uf, locals) ? 1 : 0;
         };
     }
 }
 
 export class GTE extends OBInstruction {
     ArgTypeId;
     LeftIdx;
     RightIdx;
     RetIdx;
 
     init(code, builder, instructions, i) {
         this.ArgTypeId = (code >> 20) & 0xF;
         this.LeftIdx = (code >> 14) & 0x3f;
         this.RightIdx = (code >> 7) & 0x7f;
         this.RetIdx = code & 0x7f;
     }
 
     link(builder, instructions, idx) {
         let regArr;
         switch (this.ArgTypeId) {
             case 0:
                 regArr = builder.LongRegister;
                 break;
             case 1:
                 regArr = builder.DoubleRegister;
                 break;
             case 2:
                 regArr = builder.StringRegister;
                 return;
             default:
                 throw Error("不支持类型：" + this.ArgTypeId);
         }
         let LeftReg = regArr[this.LeftIdx];
         let RightReg = regArr[this.RightIdx];
         builder.LongRegister[this.RetIdx] = (st, uf, locals) => {
             return LeftReg(st, uf, locals) >= RightReg(st, uf, locals) ? 1 : 0;
         };
     }
 }
 export class DestroyFSM extends OBInstruction {
     link(builder, instructions, idx) {
         builder.PushAction((st, uf, locals, pos) => {
             st.fsm.Destroy();
             throw new ChangeDestroyException();
         });
     }
 }
 export class FSMBroadcastMsg extends OBInstruction {
     TitleIdx;
     BodyTypeID;
     BodyRegisterIdx;
 
     init(code, builder, instructions, i) {
         this.TitleIdx = ((code >> 10) & 0x7F);
         this.BodyTypeID = ((code >> 6) & 0xF);
         this.BodyRegisterIdx = (code & 0x3F);
     }
 
     link(builder, instructions, idx) {
         let f_title = builder.StringRegister[this.TitleIdx];
         let f_body = this.makeBody(builder);
         builder.PushAction((st, uf, locals, pos) => {
             let title = f_title(st, uf, locals);
             let body = f_body(st, uf, locals);
             st.fsm.VM.BroadcastMessage(new OBUserMessage(title, OBMessage.ArgTypeOf(this.BodyTypeID, body), body), st.fsm);
             return ++pos;
         });
     }
     /**
          *
          * @param {OBFunctionBuilder} builder
          * @returns
          */
     makeBody(builder) {
         switch (this.BodyTypeID) {
             case 0xF:
                 return (st, uf, locals) => null;
             case 0:
                 var l = builder.LongRegister[this.BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return l(st, uf, locals);
                 };
             case 1:
                 var d = builder.DoubleRegister[this.BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return d(st, uf, locals);
                 };
             case 2:
                 var s = builder.StringRegister[this.BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return s(st, uf, locals);
                 };
             case 3:
                 var s1 = builder.StructRegister[this.BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return s1(st, uf, locals);
                 };
             case 4:
                 var n = builder.NObjectRegister[this.BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return n(st, uf, locals);
                 };
             default:
                 throw Error("Unknown type " + this.BodyTypeID);
         }
     }
 }
 
 /**
  * 单元数操作
  */
 export class SGLF extends OBInstruction {
     Opcode;
     value;
 
     init(code, builder, instructions, i) {
         this.value = (code & 0xFFFF);
         this.Opcode = (code >> 16) & 0xff;
     }
 
     link(builder, instructions, idx) {
         let value = this.value;
         let f_value = builder.DoubleRegister[this.value];
         if (f_value == null) {
             throw Error("left is null");
         }
         switch (this.Opcode) {
             case 0:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return -f_value(s, f, l);
                 };
                 break;
             case 1:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.log(f_value(s, f, l));
                 };
                 break;
             case 2:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.log10(f_value(s, f, l));
                 };
                 break;
             case 3:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.exp(f_value(s, f, l));
                 };
                 break;
             case 4:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.pow(10, f_value(s, f, l));
                 };
                 break;
             case 5:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.sqrt(f_value(s, f, l));
                 };
                 break;
             case 6:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.abs(f_value(s, f, l));
                 };
                 break;
             case 7:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.sin(f_value(s, f, l));
                 };
                 break;
             case 8:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.cos(f_value(s, f, l));
                 };
                 break;
             case 9:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.tan(f_value(s, f, l));
                 };
                 break;
             case 10:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.asin(f_value(s, f, l));
                 };
                 break;
             case 11:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.acos(f_value(s, f, l));
                 };
                 break;
             case 12:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.atan(f_value(s, f, l));
                 };
                 break;
             case 13:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.round(f_value(s, f, l));
                 };
                 break;
             case 14:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.ceil(f_value(s, f, l));
                 };
                 break;
             case 15:
                 builder.DoubleRegister[value] = (s, f, l) => {
                     return Math.floor(f_value(s, f, l));
                 };
                 break;
         }
     }
 }
 export class RAND extends OBInstruction {
     Register;
 
     init(code, builder, instructions, i) {
         this.Register = (code & 0xFFFFFF);
     }
 
     link(builder, instructions, idx) {
         builder.DoubleRegister[this.Register] = (st, f, l) => {
             return Math.random();
         };
     }
 }
 export class F2I extends OBInstruction {
     intRegIdx;
     floatRegIdx;
 
     init(code, builder, instructions, i) {
         this.intRegIdx = ((code) >> 12) & 0xFFF;
         this.floatRegIdx = ((code) & 0xFFF);
     }
 
     link(builder, instructions, idx) {
         let g = builder.DoubleRegister[this.floatRegIdx];
         builder.LongRegister[this.intRegIdx] = (st, uf, locals) => {
             return Math.trunc(g(st, uf, locals));
         };
     }
 }
 export class FSMSendMsgWait_Data extends OBInstruction {
     TitleIdx;
     TargetIdx;
     BodyTypeID;
     BodyRegisterIdx;
 
     init(code, builder, instructions, i) {
         this.TargetIdx = ((code >> 17) & 0x7F);
         this.TitleIdx = ((code >> 10) & 0x7F);
         this.BodyTypeID = ((code >> 6) & 0xF);
         this.BodyRegisterIdx = (code & 0x3F);
     }
 }
 export class FSMSendMsgWait extends OBInstruction {
     waitMilliSecondIdx;
 
     init(code, builder, instructions, i) {
         this.waitMilliSecondIdx = ((code >> 17) & 0x3F);
     }
 
     link(builder, instructions, idx) {
         let anchor = instructions[idx - 1];
         if (!(anchor instanceof FSMSendMsgWait_Data)) {
             throw Error("字节码错误");
         }
         let f_title = builder.StringRegister[anchor.TitleIdx];
         let f_body = this.makeBody(builder, anchor.BodyTypeID, anchor.BodyRegisterIdx);
         let waitTime = builder.LongRegister[this.waitMilliSecondIdx];
         let f_fsm = builder.NObjectRegister[anchor.TargetIdx];
         builder.PushAction((st, uf, locals, pos) => {
             let title = f_title(st, uf, locals);
             let body = f_body(st, uf, locals);
             let waitSecond = waitTime(st, uf, locals);
             let FSM = st.fsm;
             let fsm = f_fsm(st, uf, locals);
             if (!fsm) {
                 FSM.VM.Log("未找到发送目标");
                 return;
             }
             if (!(fsm instanceof OBVMFSM)) {
                 throw Error("字节码错误");
             }
             fsm.VM.Schedule(waitSecond, (VM) => {
                 fsm.PostMessage(new OBUserMessage(title, OBMessage.ArgTypeOf(anchor.BodyTypeID, body), body), FSM);
             });
             return ++pos;
         });
     }
 
     makeBody(builder, BodyTypeID, BodyRegisterIdx) {
         switch (BodyTypeID) {
             case 0xF:
                 return (st, uf, locals) => null;
             case 0:
                 var l = builder.LongRegister[BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return l(st, uf, locals);
                 };
             case 1:
                 var d = builder.DoubleRegister[BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return d(st, uf, locals);
                 };
             case 2:
                 var s = builder.StringRegister[BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return s(st, uf, locals);
                 };
             case 3:
                 var s1 = builder.StructRegister[BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return s1(st, uf, locals);
                 };
             case 4:
                 var n = builder.NObjectRegister[BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return n(st, uf, locals);
                 };
             default:
                 throw Error("Unknown type " + BodyTypeID);
         }
     }
 }
 export class FSMBroadcastMsgWait extends OBInstruction {
     TitleIdx;
     BodyTypeID;
     BodyRegisterIdx;
     waitMilliSecondIdx;
 
     init(code, builder, instructions, i) {
         this.TitleIdx = ((code >> 10) & 0x7F);
         this.BodyTypeID = ((code >> 6) & 0xF);
 
         this.BodyRegisterIdx = (code & 0x3F);
         this.waitMilliSecondIdx = ((code >> 17) & 0x3F);
         ;
     }
 
     link(builder, instructions, idx) {
         let f_title = builder.StringRegister[this.TitleIdx];
         let f_body = this.makeBody(builder);
         let waitTime = builder.LongRegister[this.waitMilliSecondIdx];
         builder.PushAction((st, uf, locals, pos) => {
             let title = f_title(st, uf, locals);
             let body = f_body(st, uf, locals);
             let waitSecond = waitTime(st, uf, locals);
             let fsm = st.fsm;
             fsm.VM.Schedule(waitSecond, (VM) => {
                 VM.BroadcastMessage(new OBUserMessage(title, OBMessage.ArgTypeOf(this.BodyTypeID, body), body, fsm));
             });
             return ++pos;
         });
     }
 
     makeBody(builder) {
         switch (this.BodyTypeID) {
             case 0xF:
                 return (st, uf, locals) => null;
             case 0:
                 var l = builder.LongRegister[this.BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return l(st, uf, locals);
                 };
             case 1:
                 var d = builder.DoubleRegister[this.BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return d(st, uf, locals);
                 };
             case 2:
                 var s = builder.StringRegister[this.BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return s(st, uf, locals);
                 };
             case 3:
                 var s1 = builder.StructRegister[this.BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return s1(st, uf, locals);
                 };
             case 4:
                 var n = builder.NObjectRegister[this.BodyRegisterIdx];
                 return (st, uf, locals) => {
                     return n(st, uf, locals);
                 };
             default:
                 throw Error("Unknown type " + this.BodyTypeID);
         }
     }
 }
 export class TextJoin extends OBInstruction {
     Left;
     Right;
     RetReg;
 
     init(code, builder, instructions, i) {
         this.Left = (code >> 17) & 0xFF;
         this.Right = (code >> 9) & 0xff;
         this.RetReg = (code & 0xFF);
     }
 
     link(builder, instructions, idx) {
         var l = builder.StringRegister[this.Left];
         var r = builder.StringRegister[this.Right];
         builder.StringRegister[this.RetReg] = (st, f, local) => {
             return l(st, f, local) + r(st, f, local);
         };
     }
 }
 export class ToString extends OBInstruction {
     ValueType;
     ValueRegIdx;
     RetRegIdx;
 
     init(code, builder, instructions, i) {
         this.ValueType = (code >> 20) & 0xF;
         this.ValueRegIdx = (code >> 10) & 0x1ff;
         this.RetRegIdx = (code & 0x1FF);
     }
 
     link(builder, instructions, idx) {
         switch (this.ValueType) {
             case 0:
                 var getl = builder.LongRegister[this.ValueRegIdx];
                 builder.StringRegister[this.RetRegIdx] = (st, f, l) => {
                     return getl(st, f, l).toString();
                 };
                 break;
             case 1:
                 var getd = builder.DoubleRegister[this.ValueRegIdx];
                 builder.StringRegister[this.RetRegIdx] = (st, f, l) => {
                     return getd(st, f, l).toString();
                 };
                 break;
             case 2:
                 var getstr = builder.StringRegister[this.ValueRegIdx];
                 builder.StringRegister[this.RetRegIdx] = (st, f, l) => {
                     var v = getstr(st, f, l);
                     if (v == null) {
                         return "";
                     }
                     return v;
                 };
                 break;
             case 3:
                 var getstruct = builder.StructRegister[this.ValueRegIdx];
                 builder.StringRegister[this.RetRegIdx] = (st, f, l) => {
                     var v = getstruct(st, f, l);
                     if (v == null) {
                         return "";
                     }
                     return v.toString();
                 };
                 break;
             case 4:
                 var geto = builder.NObjectRegister[this.ValueRegIdx];
                 builder.StringRegister[this.RetRegIdx] = (st, f, l) => {
                     var v = geto(st, f, l);
                     if (v == null) {
                         return "";
                     }
                     return v.toString();
                 };
                 break;
             default:
                 throw Error("Unknown type:" + this.ValueType);
         }
     }
 }
 export class Sender extends OBInstruction {
     RetReg;
 
     init(code, builder, instructions, i) {
         this.RetReg = code & 0xFFFF;
     }
 
     link(builder, instructions, idx) {
         builder.NObjectRegister[this.RetReg] = (st, f, local) => {
             return st.CurrentMessageSender();
         };
     }
 }
 export class SHL extends OBInstruction {
     value; bitCount;
     init(code, builder, instructions, i) {
         this.bitCount = code & 0xFFF;
         this.value = (code & 0xFFF000) >> 12;
     }
     link(builder, instructions, idx) {
         let getV = builder.LongRegister[this.value];
         let getC = builder.LongRegister[this.bitCount];
         builder.LongRegister[this.value] = (st, f, l) => {
             let v = getV(st, f, l);
             let c = getC(st, f, l);
             if (c > 0) {
                 let r = v << c;
                 return r;
             } else {
                 let r = v >> -c;
                 return r;
             }
 
         };
     }
 }
 export class AND extends OBInstruction {
     a; b;
     init(code, builder, instructions, i) {
         this.b = code & 0xFFF;
         this.a = (code & 0xFFF000) >> 12;
     }
     link(builder, instructions, idx) {
         let getV = builder.LongRegister[this.a];
         let getC = builder.LongRegister[this.b];
         builder.LongRegister[this.a] = (st, f, l) => {
             let v = getV(st, f, l);
             let c = getC(st, f, l);
             let r = v & c;
             return r;
         };
     }
 }
 export class FIX extends OBInstruction {
     regType; regIdx;
     init(code, builder, instructions, i) {
         this.regIdx = code & 0xFFFFF;
         this.regType = (code & 0xF00000) >> 20;
     }
     link(builder, instructions, idx) {
         let v;
         let loaded = false;
         let type;
         switch (this.regType) {
             case 0:
                 type = 'LongRegister';
                 break;
             case 1:
                 type = 'DoubleRegister';
                 break;
             case 2:
                 type = 'StringRegister';
                 break;
             case 3:
                 type = 'StructRegister';
                 break;
             case 4:
                 type = 'NObjectRegister';
                 break;
             default:
                 throw Error("Unknown type:" + this.ValueType);
         }
         let getV = builder[type][this.regIdx];
         builder[type][this.regIdx] = (st, f, l) => {
             if (!loaded) {
                 v = getV(st, f, l);
             } else {
                 loaded = true;
             }
             return v;
         };
     }
 }
 /**
  * value of may by key
  */
 export class VOM extends OBInstruction {
     map;
     key;
     ValueType;
     RetRegIdx;
     init(code, builder, instructions, i) {
         this.ValueType = code & 0x3F;
         this.RetRegIdx = (code & (0x3f << 6)) >> 6;
         this.key = (code & (0x3f << 12)) >> 12;
         this.map = (code & (0x3f << 18)) >> 18;
     }
 
     link(builder, instructions, idx) {
         var getMap = builder.StructRegister[this.map];
         var getKey = builder.StringRegister[this.key];
         switch (this.ValueType) {
             case 0:
                 builder.LongRegister[this.RetRegIdx] = (st, f, l) => {
                     let m = getMap(st, f, l);
                     let k = getKey(st, f, l);
                     let v = m[k];
                     return v;
                 };
                 break;
             case 1:
                 builder.DoubleRegister[this.RetRegIdx] = (st, f, l) => {
                     let m = getMap(st, f, l);
                     let k = getKey(st, f, l);
                     let v = m[k];
                     return v;
                 };
                 break;
             case 2:
                 builder.StringRegister[this.RetRegIdx] = (st, f, l) => {
                     let m = getMap(st, f, l);
                     let k = getKey(st, f, l);
                     let v = m[k];
                     return v;
                 };
                 break;
             case 3:
                 builder.StructRegister[this.RetRegIdx] = (st, f, l) => {
                     let m = getMap(st, f, l);
                     let k = getKey(st, f, l);
                     let v = m[k];
                     if (!v) {
                         debugger
                     }
                     return v;
                 };
                 break;
             case 4:
                 builder.NObjectRegister[this.RetRegIdx] = (st, f, l) => {
                     let m = getMap(st, f, l);
                     let k = getKey(st, f, l);
                     let v = m[k];
                     return v;
                 };
                 break;
             default:
                 throw Error("Unknown type:" + this.ValueType);
         }
     }
 }
 export class LAND extends OBInstruction {
     a; b;
     init(code, builder, instructions, i) {
         this.b = code & 0xFFF;
         this.a = (code & 0xFFF000) >> 12;
     }
     link(builder, instructions, idx) {
         let getV = builder.LongRegister[this.a];
         let getC = builder.LongRegister[this.b];
         builder.LongRegister[this.a] = (st, f, l) => {
             let v = getV(st, f, l);
             if (v) {
                 let c = getC(st, f, l);
                 return !!c;
             } else {
                 return 0;
             }
         };
     }
 }
 export class LOR extends OBInstruction {
     a; b;
     init(code, builder, instructions, i) {
         this.b = code & 0xFFF;
         this.a = (code & 0xFFF000) >> 12;
     }
     link(builder, instructions, idx) {
         let getV = builder.LongRegister[this.a];
         let getC = builder.LongRegister[this.b];
         builder.LongRegister[this.a] = (st, f, l) => {
             let v = getV(st, f, l);
             if (v) {
                 return 1;
             } else {
                 let c = getC(st, f, l);
                 return !!c;
             }
         };
     }
 }
 export class LNOT extends OBInstruction {
     a;
     init(code, builder, instructions, i) {
         this.a = code & 0xFFF;
     }
     link(builder, instructions, idx) {
         let getV = builder.LongRegister[this.a];
         builder.LongRegister[this.a] = (st, f, l) => {
             let v = getV(st, f, l);
             return !v;
         };
     }
 }
 export class COND extends OBInstruction {
     if_; then_; else_; regType;
     init(code, builder, instructions, i) {
         this.regType = code & 0x3F;
         this.else_ = (code & (0x3f << 6)) >> 6;
         this.then_ = (code & (0x3f << 12)) >> 12;
         this.if_ = (code & (0x3f << 18)) >> 18;
     }
     link(builder, instructions, idx) {
         let if_ = builder.LongRegister[this.if_];
         let else_;
         let then_;
         let type;
         switch (this.regType) {
             case 0:
                 type = 'LongRegister';
                 break;
             case 1:
                 type = 'DoubleRegister';
                 break;
             case 2:
                 type = 'StringRegister';
                 break;
             case 3:
                 type = 'StructRegister';
                 break;
             case 4:
                 type = 'NObjectRegister';
                 break;
             default:
                 throw Error("Unknown type:" + this.regType);
         }
         else_ = builder[type][this.else_];
         then_ = builder[type][this.then_];
         builder[type][this.then_] = (st, f, l) => {
             let if_v = if_(st, f, l);
             if (if_v != 0) {
                 return then_(st, f, l);
             }
             return else_(st, f, l);
         };
     }
 }